From b76af8cc5b7f4464eb2ac8b99900d82eb7fca4af Mon Sep 17 00:00:00 2001 From: ADedecker Date: Sun, 26 Apr 2026 15:43:50 +0200 Subject: [PATCH 001/210] start --- Mathlib/LinearAlgebra/Projection.lean | 10 +++ .../Topology/Algebra/Module/Complement.lean | 89 +++++++++++++++++++ .../Topology/Algebra/Module/LinearMap.lean | 57 ------------ 3 files changed, 99 insertions(+), 57 deletions(-) create mode 100644 Mathlib/Topology/Algebra/Module/Complement.lean diff --git a/Mathlib/LinearAlgebra/Projection.lean b/Mathlib/LinearAlgebra/Projection.lean index ec916c60a6a827..a3625349e608b7 100644 --- a/Mathlib/LinearAlgebra/Projection.lean +++ b/Mathlib/LinearAlgebra/Projection.lean @@ -244,10 +244,20 @@ theorem IsCompl.projection_add_projection_eq_self (hpq : IsCompl p q) (x : E) : rw [← prodComm_trans_prodEquivOfIsCompl _ _ hpq] exact (prodEquivOfIsCompl _ _ hpq).apply_symm_apply x +theorem IsCompl.projection_add_projection_eq_id (hpq : IsCompl p q) : + hpq.projection + hpq.symm.projection = .id := by + ext + apply IsCompl.projection_add_projection_eq_self hpq + lemma IsCompl.projection_eq_self_sub_projection (hpq : IsCompl p q) (x : E) : hpq.symm.projection x = x - hpq.projection x := by rw [eq_sub_iff_add_eq, projection_add_projection_eq_self] +lemma IsCompl.projection_eq_id_sub_projection (hpq : IsCompl p q) : + hpq.symm.projection = .id - hpq.projection := by + ext + apply IsCompl.projection_eq_self_sub_projection hpq + /-- The projection to `p` along `q` of `x` equals `x` if and only if `x ∈ p`. -/ @[simp] lemma IsCompl.projection_eq_self_iff (hpq : IsCompl p q) (x : E) : hpq.projection x = x ↔ x ∈ p := by diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean new file mode 100644 index 00000000000000..c0c48a3cc62ca8 --- /dev/null +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -0,0 +1,89 @@ +/- +Copyright (c) 2019 Sébastien Gouëzel. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Anatole Dedecker +-/ +module + +public import Mathlib.Topology.Algebra.Module.LinearMap + +@[expose] public section + +open LinearMap (ker range) +open Topology ContinuousLinearMap + +namespace Submodule + +variable {R : Type*} [Ring R] {M : Type*} [TopologicalSpace M] [AddCommGroup M] [Module R M] + +open ContinuousLinearMap + +/-- Two submodules `p` and `q` are *topological complements* if they are algebraic complements and +the projection on `p` parallel to `q` is continuous -/ +structure IsTopCompl (p q : Submodule R M) : Prop where + isCompl : IsCompl p q + continuous_projection : Continuous (IsCompl.projection isCompl) + +/-- A submodule `p` is called *complemented* if there exists a continuous projection `M →ₗ[R] p`. -/ +def ClosedComplemented (p : Submodule R M) : Prop := + ∃ f : M →L[R] p, ∀ x : p, f x = x + +variable {p q : Submodule R M} + +namespace IsTopCompl + +theorem _root_.IsCompl.isTopCompl_iff (h : IsCompl p q) : + IsTopCompl p q ↔ Continuous (IsCompl.projection h) := + ⟨IsTopCompl.continuous_projection, fun h' ↦ ⟨h, h'⟩⟩ + +protected theorem symm (h : IsTopCompl p q) : IsTopCompl q p where + isCompl := h.isCompl.symm + continuous_projection := .congr _ (fun x ↦ IsCompl.projection_eq_self_sub_projection h.isCompl x) + +end IsTopCompl + +namespace ClosedComplemented + +variable [T1Space p] + +theorem exists_isClosed_isCompl (h : ClosedComplemented p) : + ∃ q : Submodule R M, IsClosed (q : Set M) ∧ IsCompl p q := + Exists.elim h fun f hf => ⟨ker f, isClosed_ker f, LinearMap.isCompl_of_proj hf⟩ + +/-- An arbitrary choice of closed complement of a closed complemented submodule. -/ +noncomputable def complement (h : ClosedComplemented p) : Submodule R M := + Classical.choose h.exists_isClosed_isCompl + +theorem isClosed_complement (h : ClosedComplemented p) : IsClosed (h.complement : Set M) := + Classical.choose_spec (h.exists_isClosed_isCompl) |>.1 + +theorem isCompl_complement (h : ClosedComplemented p) : IsCompl p h.complement := + Classical.choose_spec (h.exists_isClosed_isCompl) |>.2 + +protected theorem isClosed [IsTopologicalAddGroup M] [T1Space M] + {p : Submodule R M} (h : ClosedComplemented p) : IsClosed (p : Set M) := by + rcases h with ⟨f, hf⟩ + have : (ContinuousLinearMap.id R M - p.subtypeL.comp f).ker = p := + LinearMap.ker_id_sub_eq_of_proj hf + exact this ▸ isClosed_ker _ + +end ClosedComplemented + +@[simp] +theorem closedComplemented_bot : ClosedComplemented (⊥ : Submodule R M) := + ⟨0, fun x => by simp only [zero_apply, eq_zero_of_bot_submodule x]⟩ + +@[simp] +theorem closedComplemented_top : ClosedComplemented (⊤ : Submodule R M) := + ⟨(ContinuousLinearMap.id R M).codRestrict ⊤ fun _x => trivial, + fun x => Subtype.ext_iff.2 <| by simp⟩ + +end Submodule + +theorem ContinuousLinearMap.closedComplemented_ker_of_rightInverse {R : Type*} [Ring R] + {M : Type*} [TopologicalSpace M] [AddCommGroup M] {M₂ : Type*} [TopologicalSpace M₂] + [AddCommGroup M₂] [Module R M] [Module R M₂] [IsTopologicalAddGroup M] (f₁ : M →L[R] M₂) + (f₂ : M₂ →L[R] M) (h : Function.RightInverse f₂ f₁) : f₁.ker.ClosedComplemented := + ⟨f₁.projKerOfRightInverse f₂ h, f₁.projKerOfRightInverse_apply_idem f₂ h⟩ + +end diff --git a/Mathlib/Topology/Algebra/Module/LinearMap.lean b/Mathlib/Topology/Algebra/Module/LinearMap.lean index f7860d68752d09..a70a78a970b6a1 100644 --- a/Mathlib/Topology/Algebra/Module/LinearMap.lean +++ b/Mathlib/Topology/Algebra/Module/LinearMap.lean @@ -1217,63 +1217,6 @@ end Ring end RestrictScalars end ContinuousLinearMap - -namespace Submodule - -variable {R : Type*} [Ring R] {M : Type*} [TopologicalSpace M] [AddCommGroup M] [Module R M] - -open ContinuousLinearMap - -/-- A submodule `p` is called *complemented* if there exists a continuous projection `M →ₗ[R] p`. -/ -def ClosedComplemented (p : Submodule R M) : Prop := - ∃ f : M →L[R] p, ∀ x : p, f x = x - -variable {p : Submodule R M} - -namespace ClosedComplemented - -variable [T1Space p] - -theorem exists_isClosed_isCompl (h : ClosedComplemented p) : - ∃ q : Submodule R M, IsClosed (q : Set M) ∧ IsCompl p q := - Exists.elim h fun f hf => ⟨ker f, isClosed_ker f, LinearMap.isCompl_of_proj hf⟩ - -/-- An arbitrary choice of closed complement of a closed complemented submodule. -/ -noncomputable def complement (h : ClosedComplemented p) : Submodule R M := - Classical.choose h.exists_isClosed_isCompl - -theorem isClosed_complement (h : ClosedComplemented p) : IsClosed (h.complement : Set M) := - Classical.choose_spec (h.exists_isClosed_isCompl) |>.1 - -theorem isCompl_complement (h : ClosedComplemented p) : IsCompl p h.complement := - Classical.choose_spec (h.exists_isClosed_isCompl) |>.2 - -protected theorem isClosed [IsTopologicalAddGroup M] [T1Space M] - {p : Submodule R M} (h : ClosedComplemented p) : IsClosed (p : Set M) := by - rcases h with ⟨f, hf⟩ - have : (ContinuousLinearMap.id R M - p.subtypeL.comp f).ker = p := - LinearMap.ker_id_sub_eq_of_proj hf - exact this ▸ isClosed_ker _ - -end ClosedComplemented - -@[simp] -theorem closedComplemented_bot : ClosedComplemented (⊥ : Submodule R M) := - ⟨0, fun x => by simp only [zero_apply, eq_zero_of_bot_submodule x]⟩ - -@[simp] -theorem closedComplemented_top : ClosedComplemented (⊤ : Submodule R M) := - ⟨(ContinuousLinearMap.id R M).codRestrict ⊤ fun _x => trivial, - fun x => Subtype.ext_iff.2 <| by simp⟩ - -end Submodule - -theorem ContinuousLinearMap.closedComplemented_ker_of_rightInverse {R : Type*} [Ring R] - {M : Type*} [TopologicalSpace M] [AddCommGroup M] {M₂ : Type*} [TopologicalSpace M₂] - [AddCommGroup M₂] [Module R M] [Module R M₂] [IsTopologicalAddGroup M] (f₁ : M →L[R] M₂) - (f₂ : M₂ →L[R] M) (h : Function.RightInverse f₂ f₁) : f₁.ker.ClosedComplemented := - ⟨f₁.projKerOfRightInverse f₂ h, f₁.projKerOfRightInverse_apply_idem f₂ h⟩ - namespace ContinuousLinearMap @[grind =] From 2bd23178a4bbd5ea60cc22be9c1beba1a6f42f40 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Sun, 26 Apr 2026 15:44:43 +0200 Subject: [PATCH 002/210] mk_all --- Mathlib.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/Mathlib.lean b/Mathlib.lean index b6292c78b1ffa9..798ab9bafd5a89 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -7355,6 +7355,7 @@ public import Mathlib.Topology.Algebra.Module.Basic public import Mathlib.Topology.Algebra.Module.Cardinality public import Mathlib.Topology.Algebra.Module.ClosedSubmodule public import Mathlib.Topology.Algebra.Module.Compact +public import Mathlib.Topology.Algebra.Module.Complement public import Mathlib.Topology.Algebra.Module.Determinant public import Mathlib.Topology.Algebra.Module.Equiv public import Mathlib.Topology.Algebra.Module.FiniteDimension From 977524c9fe1cf0c0241931963308f78944dc6b2e Mon Sep 17 00:00:00 2001 From: ADedecker Date: Mon, 27 Apr 2026 14:22:21 +0200 Subject: [PATCH 003/210] Main API done --- Mathlib/LinearAlgebra/Projection.lean | 16 +- .../Topology/Algebra/Module/Complement.lean | 277 +++++++++++++++--- .../Topology/Algebra/Module/LinearMap.lean | 1 - 3 files changed, 257 insertions(+), 37 deletions(-) diff --git a/Mathlib/LinearAlgebra/Projection.lean b/Mathlib/LinearAlgebra/Projection.lean index a3625349e608b7..dfa0be311c6a10 100644 --- a/Mathlib/LinearAlgebra/Projection.lean +++ b/Mathlib/LinearAlgebra/Projection.lean @@ -197,14 +197,26 @@ theorem IsCompl.projection_apply_eq_zero_iff (hpq : IsCompl p q) {x : E} : hpq.projection x = 0 ↔ x ∈ q := by simp [projection, -coe_linearProjOfIsCompl_apply] +alias ⟨_, linearProjOfIsCompl_apply_of_mem_right⟩ := + linearProjOfIsCompl_apply_eq_zero_iff + +@[deprecated linearProjOfIsCompl_apply_of_mem_right (since := "2026-04-27")] theorem linearProjOfIsCompl_apply_right' (h : IsCompl p q) (x : E) (hx : x ∈ q) : linearProjOfIsCompl p q h x = 0 := - (linearProjOfIsCompl_apply_eq_zero_iff h).2 hx + linearProjOfIsCompl_apply_of_mem_right h hx + +alias ⟨_, IsCompl.projection_apply_of_mem_right⟩ := + IsCompl.projection_apply_eq_zero_iff @[simp] theorem linearProjOfIsCompl_apply_right (h : IsCompl p q) (x : q) : linearProjOfIsCompl p q h x = 0 := - linearProjOfIsCompl_apply_right' h x x.2 + linearProjOfIsCompl_apply_of_mem_right h x.2 + +@[simp] +theorem IsCompl.projection_apply_right (h : IsCompl p q) (x : q) : + h.projection x = 0 := + h.projection_apply_of_mem_right x.2 @[simp] theorem linearProjOfIsCompl_ker (h : IsCompl p q) : ker (linearProjOfIsCompl p q h) = q := diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index c0c48a3cc62ca8..949395ea221962 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -1,20 +1,26 @@ /- Copyright (c) 2019 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Anatole Dedecker +Authors: Jan-David Salchow, Sébastien Gouëzel, Jean Lo, Yury Kudryashov, Frédéric Dupuis, + Heather Macbeth, Anatole Dedecker -/ module public import Mathlib.Topology.Algebra.Module.LinearMap +/-! +# TODO +-/ + @[expose] public section open LinearMap (ker range) -open Topology ContinuousLinearMap +open Topology ContinuousLinearMap Function namespace Submodule -variable {R : Type*} [Ring R] {M : Type*} [TopologicalSpace M] [AddCommGroup M] [Module R M] +variable {R : Type*} [Ring R] {M N : Type*} [TopologicalSpace M] [TopologicalSpace N] + [AddCommGroup M] [AddCommGroup N] [Module R M] [Module R N] open ContinuousLinearMap @@ -30,60 +36,263 @@ def ClosedComplemented (p : Submodule R M) : Prop := variable {p q : Submodule R M} -namespace IsTopCompl +section IsTopCompl theorem _root_.IsCompl.isTopCompl_iff (h : IsCompl p q) : IsTopCompl p q ↔ Continuous (IsCompl.projection h) := ⟨IsTopCompl.continuous_projection, fun h' ↦ ⟨h, h'⟩⟩ -protected theorem symm (h : IsTopCompl p q) : IsTopCompl q p where +protected theorem IsTopCompl.symm [ContinuousSub M] (h : IsTopCompl p q) : IsTopCompl q p where isCompl := h.isCompl.symm - continuous_projection := .congr _ (fun x ↦ IsCompl.projection_eq_self_sub_projection h.isCompl x) + continuous_projection := by + rw [IsCompl.projection_eq_id_sub_projection h.isCompl] + exact continuous_id.sub h.continuous_projection + +theorem _root_.IsIdempotentElem.isTopCompl {f : M →L[R] M} (hf : IsIdempotentElem f) : + IsTopCompl f.range f.ker := by + rw [← isIdempotentElem_toLinearMap_iff] at hf + refine ⟨LinearMap.IsIdempotentElem.isCompl hf, ?_⟩ + rw [← LinearMap.IsIdempotentElem.eq_isCompl_projection hf] + exact f.continuous + +theorem isTopCompl_bot_top : + IsTopCompl (⊥ : Submodule R M) ⊤ := by + have : IsIdempotentElem (0 : M →L[R] M) := .zero + simpa using this.isTopCompl + +theorem isTopCompl_top_bot : + IsTopCompl (⊤ : Submodule R M) ⊥ := by + have : IsIdempotentElem (.id R M : M →L[R] M) := .one + simpa using this.isTopCompl + +open LinearMap in +theorem _root_.ContinuousLinearMap.isTopCompl_range_ker_of_leftInverse + (f₁ : M →L[R] N) (f₂ : N →L[R] M) (h : Function.LeftInverse f₂ f₁) : + f₁.range.IsTopCompl f₂.ker := + let p := f₁ ∘L f₂ + have p_idem : IsIdempotentElem p := by ext x; simp [p, h (f₂ x)] + have range_p : p.range = f₁.range := range_comp_of_range_eq_top _ <| + range_eq_top_of_surjective _ h.surjective + have ker_p : p.ker = f₂.ker := ker_comp_of_ker_eq_bot _ <| + ker_eq_bot_of_injective h.injective + range_p ▸ ker_p ▸ p_idem.isTopCompl + +theorem _root_.ContinuousLinearMap.isTopCompl_of_proj {f : M →L[R] p} (hf : ∀ x : p, f x = x) : + IsTopCompl p f.ker := by + simpa using p.subtypeL.isTopCompl_range_ker_of_leftInverse f hf + +section projectionOnto + +protected noncomputable def IsTopCompl.projectionOnto (h : IsTopCompl p q) : M →L[R] p := + ⟨p.linearProjOfIsCompl q h.isCompl, by + rw [IsInducing.subtypeVal.continuous_iff] + exact h.continuous_projection⟩ + +@[simp] +theorem IsTopCompl.projectionOnto_toLinearMap (h : IsTopCompl p q) : + (h.projectionOnto : M →ₗ[R] p) = p.linearProjOfIsCompl q h.isCompl := + rfl + +@[simp] +theorem IsTopCompl.projectionOnto_apply_left (h : IsTopCompl p q) (x : p) : + h.projectionOnto x = x := + linearProjOfIsCompl_apply_left h.isCompl x + +@[simp] +theorem IsTopCompl.range_projectionOnto (h : IsTopCompl p q) : h.projectionOnto.range = ⊤ := + linearProjOfIsCompl_range h.isCompl + +theorem IsTopCompl.projectionOnto_surjective (h : IsTopCompl p q) : Surjective h.projectionOnto := + linearProjOfIsCompl_surjective h.isCompl + +@[simp] +theorem IsTopCompl.projectionOnto_apply_eq_zero_iff (h : IsTopCompl p q) {x : M} : + h.projectionOnto x = 0 ↔ x ∈ q := + linearProjOfIsCompl_apply_eq_zero_iff h.isCompl + +alias ⟨_, IsTopCompl.projectionOnto_apply_eq_zero_of_mem_right⟩ := + IsTopCompl.projectionOnto_apply_eq_zero_iff + +@[simp] +theorem IsTopCompl.projectionOnto_apply_right (h : IsTopCompl p q) (x : q) : + h.projectionOnto x = 0 := + h.projectionOnto_apply_eq_zero_of_mem_right x.2 + +theorem IsTopCompl.ker_projectionOnto (h : IsTopCompl p q) : + ker (h.projectionOnto : M →ₗ[R] p) = q := + linearProjOfIsCompl_ker h.isCompl + +theorem IsTopCompl.isQuotientMap_projectionOnto (h : IsTopCompl p q) : + IsQuotientMap h.projectionOnto := + .of_inverse continuous_subtype_val h.projectionOnto.continuous h.projectionOnto_apply_left + +-- TODO: more API + +end projectionOnto + +section projection + +protected noncomputable def IsTopCompl.projection (h : IsTopCompl p q) : M →L[R] M := + p.subtypeL ∘L h.projectionOnto + +@[simp] +theorem IsTopCompl.projection_toLinearMap (h : IsTopCompl p q) : + (h.projection : M →ₗ[R] M) = IsCompl.projection h.isCompl := + rfl + +theorem IsTopCompl.projection_apply (h : IsTopCompl p q) (x : M) : + h.projection x = h.projectionOnto x := + rfl + +@[simp] +theorem IsTopCompl.coe_projectionOnto_apply (h : IsTopCompl p q) (x : M) : + (h.projectionOnto x : M) = h.projection x := + rfl + +@[simp] +theorem IsTopCompl.projection_apply_mem (h : IsTopCompl p q) (x : M) : + h.projection x ∈ p := + SetLike.coe_mem _ + +@[simp] +theorem IsTopCompl.projection_apply_left (h : IsTopCompl p q) (x : p) : + h.projection x = x := + IsCompl.projection_apply_left h.isCompl x + +@[simp] +theorem IsTopCompl.range_projection (h : IsTopCompl p q) : + h.projection.range = p := + IsCompl.projection_range h.isCompl + +@[simp] +theorem IsTopCompl.projection_apply_eq_zero_iff (h : IsTopCompl p q) {x : M} : + h.projection x = 0 ↔ x ∈ q := + IsCompl.projection_apply_eq_zero_iff h.isCompl + +alias ⟨_, IsTopCompl.projection_apply_eq_zero_of_mem_right⟩ := + IsTopCompl.projection_apply_eq_zero_iff + +@[simp] +theorem IsTopCompl.projection_apply_right (h : IsTopCompl p q) (x : q) : + h.projection x = 0 := + h.projection_apply_eq_zero_of_mem_right x.2 + +@[simp] +theorem IsTopCompl.projection_isIdempotentElem (h : IsTopCompl p q) : + IsIdempotentElem h.projection := by + simp [← isIdempotentElem_toLinearMap_iff] + +theorem IsTopCompl.projection_add_projection_eq_self [ContinuousSub M] + (h : IsTopCompl p q) (x : M) : + h.projection x + h.symm.projection x = x := + IsCompl.projection_add_projection_eq_self h.isCompl x + +theorem IsTopCompl.projection_add_projection_eq_id [IsTopologicalAddGroup M] (h : IsTopCompl p q) : + h.projection + h.symm.projection = .id R M := by + ext + apply h.projection_add_projection_eq_self + +lemma IsTopCompl.projection_eq_self_sub_projection [ContinuousSub M] (h : IsTopCompl p q) (x : M) : + h.symm.projection x = x - h.projection x := by + rw [eq_sub_iff_add_eq, projection_add_projection_eq_self] + +lemma IsTopCompl.projection_eq_id_sub_projection [IsTopologicalAddGroup M] (h : IsTopCompl p q) : + h.symm.projection = .id R M - h.projection := by + ext + apply h.projection_eq_self_sub_projection + +/-- The projection to `p` along `q` of `x` equals `x` if and only if `x ∈ p`. -/ +@[simp] lemma IsTopCompl.projection_eq_self_iff [ContinuousSub M] (h : IsTopCompl p q) (x : M) : + h.projection x = x ↔ x ∈ p := + IsCompl.projection_eq_self_iff h.isCompl x + +end projection + +section closed_hausdorff + +theorem IsTopCompl.closedComplemented (h : IsTopCompl p q) : ClosedComplemented p := + ⟨h.projectionOnto, h.projectionOnto_apply_left⟩ + +/-- A variant of `Submodule.IsTopCompl.isClosed`. This has the very mild advantage over +`h.symm.isClosed` that it doesn't assume `ContinuousSub M`. -/ +theorem IsTopCompl.isClosed' [T1Space p] (h : IsTopCompl p q) : IsClosed (q : Set M) := by + rw [← ker_projectionOnto h] + exact isClosed_ker _ + +protected theorem IsTopCompl.isClosed [T1Space q] [ContinuousSub M] (h : IsTopCompl p q) : + IsClosed (p : Set M) := + h.symm.isClosed' + +protected theorem IsTopCompl.t3Space [IsTopologicalAddGroup M] (h : IsTopCompl p q) + (hq : IsClosed (q : Set M)) : T3Space p := by + have : IsClosed ({0} : Set p) := by + rw [← h.isQuotientMap_projectionOnto.isClosed_preimage] + rwa [← h.ker_projectionOnto] at hq + have : T1Space p := IsTopologicalAddGroup.t1Space _ this + rw [RegularSpace.t3Space_iff_t0Space] + infer_instance + +protected theorem IsTopCompl.t2Space [IsTopologicalAddGroup M] (h : IsTopCompl p q) + (hq : IsClosed (q : Set M)) : T2Space p := + have := h.t3Space hq + inferInstance + +end closed_hausdorff end IsTopCompl -namespace ClosedComplemented +section ClosedComplemented -variable [T1Space p] +theorem ClosedComplemented.exists_isTopCompl (h : ClosedComplemented p) : + ∃ q : Submodule R M, IsTopCompl p q := + Exists.elim h fun f hf => ⟨_, f.isTopCompl_of_proj hf⟩ -theorem exists_isClosed_isCompl (h : ClosedComplemented p) : +theorem closedComplemented_iff_exists_isTopCompl : + ClosedComplemented p ↔ ∃ q, IsTopCompl p q := + ⟨ClosedComplemented.exists_isTopCompl, fun H ↦ H.elim fun _ hq ↦ hq.closedComplemented⟩ + +@[deprecated ClosedComplemented.exists_isTopCompl (since := "2026-04-27")] +theorem ClosedComplemented.exists_isClosed_isCompl [T1Space p] (h : ClosedComplemented p) : ∃ q : Submodule R M, IsClosed (q : Set M) ∧ IsCompl p q := - Exists.elim h fun f hf => ⟨ker f, isClosed_ker f, LinearMap.isCompl_of_proj hf⟩ + Exists.elim h.exists_isTopCompl fun q hq => ⟨q, hq.isClosed', hq.isCompl⟩ -/-- An arbitrary choice of closed complement of a closed complemented submodule. -/ -noncomputable def complement (h : ClosedComplemented p) : Submodule R M := - Classical.choose h.exists_isClosed_isCompl +/-- An arbitrary choice of topological complement of a closed complemented submodule. -/ +noncomputable def ClosedComplemented.complement (h : ClosedComplemented p) : Submodule R M := + Classical.choose h.exists_isTopCompl -theorem isClosed_complement (h : ClosedComplemented p) : IsClosed (h.complement : Set M) := - Classical.choose_spec (h.exists_isClosed_isCompl) |>.1 +theorem ClosedComplemented.isTopCompl_complement (h : ClosedComplemented p) : + IsTopCompl p h.complement := + Classical.choose_spec h.exists_isTopCompl -theorem isCompl_complement (h : ClosedComplemented p) : IsCompl p h.complement := - Classical.choose_spec (h.exists_isClosed_isCompl) |>.2 +theorem ClosedComplemented.isCompl_complement (h : ClosedComplemented p) : IsCompl p h.complement := + h.isTopCompl_complement.isCompl -protected theorem isClosed [IsTopologicalAddGroup M] [T1Space M] - {p : Submodule R M} (h : ClosedComplemented p) : IsClosed (p : Set M) := by - rcases h with ⟨f, hf⟩ - have : (ContinuousLinearMap.id R M - p.subtypeL.comp f).ker = p := - LinearMap.ker_id_sub_eq_of_proj hf - exact this ▸ isClosed_ker _ +theorem ClosedComplemented.isClosed_complement [T1Space p] (h : ClosedComplemented p) : + IsClosed (h.complement : Set M) := + h.isTopCompl_complement.isClosed' -end ClosedComplemented +protected theorem ClosedComplemented.isClosed [ContinuousSub M] [T1Space M] + {p : Submodule R M} (h : ClosedComplemented p) : IsClosed (p : Set M) := + h.isTopCompl_complement.isClosed @[simp] theorem closedComplemented_bot : ClosedComplemented (⊥ : Submodule R M) := - ⟨0, fun x => by simp only [zero_apply, eq_zero_of_bot_submodule x]⟩ + isTopCompl_bot_top.closedComplemented @[simp] theorem closedComplemented_top : ClosedComplemented (⊤ : Submodule R M) := - ⟨(ContinuousLinearMap.id R M).codRestrict ⊤ fun _x => trivial, - fun x => Subtype.ext_iff.2 <| by simp⟩ + isTopCompl_top_bot.closedComplemented -end Submodule +theorem _root_.ContinuousLinearMap.closedComplemented_range_of_leftInverse + (f₁ : M →L[R] N) (f₂ : N →L[R] M) (h : Function.LeftInverse f₂ f₁) : + f₁.range.ClosedComplemented := + f₁.isTopCompl_range_ker_of_leftInverse f₂ h |>.closedComplemented + +theorem _root_.ContinuousLinearMap.closedComplemented_ker_of_rightInverse [ContinuousSub M] + (f₁ : M →L[R] N) (f₂ : N →L[R] M) (h : Function.RightInverse f₂ f₁) : + f₁.ker.ClosedComplemented := + f₂.isTopCompl_range_ker_of_leftInverse f₁ h.leftInverse |>.symm.closedComplemented -theorem ContinuousLinearMap.closedComplemented_ker_of_rightInverse {R : Type*} [Ring R] - {M : Type*} [TopologicalSpace M] [AddCommGroup M] {M₂ : Type*} [TopologicalSpace M₂] - [AddCommGroup M₂] [Module R M] [Module R M₂] [IsTopologicalAddGroup M] (f₁ : M →L[R] M₂) - (f₂ : M₂ →L[R] M) (h : Function.RightInverse f₂ f₁) : f₁.ker.ClosedComplemented := - ⟨f₁.projKerOfRightInverse f₂ h, f₁.projKerOfRightInverse_apply_idem f₂ h⟩ +end ClosedComplemented -end +end Submodule diff --git a/Mathlib/Topology/Algebra/Module/LinearMap.lean b/Mathlib/Topology/Algebra/Module/LinearMap.lean index a70a78a970b6a1..4f8322288e7820 100644 --- a/Mathlib/Topology/Algebra/Module/LinearMap.lean +++ b/Mathlib/Topology/Algebra/Module/LinearMap.lean @@ -962,7 +962,6 @@ section variable {σ₂₁ : R₂ →+* R} [RingHomInvPair σ₁₂ σ₂₁] - /-- Given a right inverse `f₂ : M₂ →L[R] M` to `f₁ : M →L[R] M₂`, `projKerOfRightInverse f₁ f₂ h` is the projection `M →L[R] LinearMap.ker f₁` along `LinearMap.range f₂`. -/ From aea474121fa30cb6a24eba48b30657152d2f1105 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Mon, 27 Apr 2026 15:12:51 +0200 Subject: [PATCH 004/210] Ready for review? --- .../Topology/Algebra/Module/Complement.lean | 76 +++++++++++++++++-- 1 file changed, 71 insertions(+), 5 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 949395ea221962..5660b1605745d0 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -9,7 +9,64 @@ module public import Mathlib.Topology.Algebra.Module.LinearMap /-! -# TODO +# Topological complements of submodules + +Let `M` be a topological `R`-module. Two submodules `p, q` of `M` are said to be +*topological complements* (`Submodule.IsTopCompl`) if they are algebraic complements and the +algebraic isomorphism `M ≃ p × q` is an homeomorphism. + +Not all submodules of `M` admit such a topological complements (even if they admit algebraic +complements). In the litterature, such a submodule is called *topologically complemented* +or *direct*. One may also find the terminology *closed complemented* because, +in a Banach space, a closed algebraic complement is automatically a topological complement. +This is the terminology we use for now (`Submodule.ClosedComplemented`), but we should eventually +change to something less misleading. + +## Main definitions + +* `Submodule.IsTopCompl`: we say that two submodules are *topological complements* if they are + algebraic complements and the projection on `p` parallel to `q` is continuous. This is equivalent + to the definition given above. +* `Submodule.ClosedComplemented`: we say that a submodule is (topologically) *complemented* if + there exists a continuous projection `M →ₗ[R] p`. +* `Submodule.IsTopCompl.projectionOnto`: if `h : IsTopCompl p q`, `h.projectionOnto` is the + continuous linear projection `M →L[R] p` parallel to `q`. This is the continuous version of + `Submodule.linearProjOfIsCompl`. +* `Submodule.IsTopCompl.projection`: if `h : IsTopCompl p q`, `h.projection` is the continuous + linear projection `M →L[R] M` onto `p` parallel to `q`. This is the continuous version of + `Submodule.IsCompl.projection`. +* `Submodule.ClosedComplemented.complement`: an arbitrary topological complement of a topologically + complemented submodule. + +## Main statements + +* `IsIdempotentElem.isTopCompl`: the range and kernel of a continuous projection are topological + complements. +* `Submodule.IsTopCompl.isClosed`: if `p` and `q` are topological complements in a Hausdorff space, + they are closed. + +## Implementation details + +In the definition of `Submodule.IsTopCompl`, we choose to ask for the continuity of the projection +on the left submdule parallel to the right one, because it is a simpler map to work with than the +map `M ≃ p × q`. + +Because the condition is symmetric, a lot of lemmas could have a left and a right variation. +In general we only include the left version, the right one being accessible through +`Submodule.IsTopCompl.symm`. + +## TODO + +There is still a significant part of the algebraic API which should be ported to the +topological setting. Notably, we should: +* show that `Submodule.prodEquivOfIsCompl` is an homeomorphism if and only if + the two subspaces are topological complements, and bundle it as a `ContinuousLinearEquiv` when + this is the case. +* show that `Submodule.quotientEquivOfIsCompl` is an homeomorphism if and only if + the two subspaces are topological complements, and bundle it as a `ContinuousLinearEquiv` when + this is the case. +* define `ContinuousLinearMap.ofIsTopCompl`, analogous to `LinearMap.ofIsCompl`. + -/ @[expose] public section @@ -25,7 +82,7 @@ variable {R : Type*} [Ring R] {M N : Type*} [TopologicalSpace M] [TopologicalSpa open ContinuousLinearMap /-- Two submodules `p` and `q` are *topological complements* if they are algebraic complements and -the projection on `p` parallel to `q` is continuous -/ +the projection on `p` parallel to `q` is continuous. -/ structure IsTopCompl (p q : Submodule R M) : Prop where isCompl : IsCompl p q continuous_projection : Continuous (IsCompl.projection isCompl) @@ -83,6 +140,10 @@ theorem _root_.ContinuousLinearMap.isTopCompl_of_proj {f : M →L[R] p} (hf : section projectionOnto +/-- If `h : IsTopCompl p q`, `h.projectionOnto` is the continuous linear projection `M →L[R] p` +parallel to `q`. This is the continuous version of `Submodule.linearProjOfIsCompl`. + +See also `Submodule.IsTopCompl.projection` for the same projection as an element of `M →L[R] M`. -/ protected noncomputable def IsTopCompl.projectionOnto (h : IsTopCompl p q) : M →L[R] p := ⟨p.linearProjOfIsCompl q h.isCompl, by rw [IsInducing.subtypeVal.continuous_iff] @@ -126,12 +187,15 @@ theorem IsTopCompl.isQuotientMap_projectionOnto (h : IsTopCompl p q) : IsQuotientMap h.projectionOnto := .of_inverse continuous_subtype_val h.projectionOnto.continuous h.projectionOnto_apply_left --- TODO: more API - end projectionOnto section projection +/-- If `h : IsTopCompl p q`, `h.projection` is the continuous linear projection `M →L[R] M` onto +`p` parallel to `q`. This is the continuous version of `Submodule.IsCompl.projection`. + +See also `Submodule.IsTopCompl.projectionOnto` for the same projection as an element of +`M →L[R] p`. -/ protected noncomputable def IsTopCompl.projection (h : IsTopCompl p q) : M →L[R] M := p.subtypeL ∘L h.projectionOnto @@ -219,10 +283,12 @@ theorem IsTopCompl.isClosed' [T1Space p] (h : IsTopCompl p q) : IsClosed (q : Se rw [← ker_projectionOnto h] exact isClosed_ker _ +/-- If `p` and `q` are topological complements and `q` is Hausdorff, then `p` is closed. -/ protected theorem IsTopCompl.isClosed [T1Space q] [ContinuousSub M] (h : IsTopCompl p q) : IsClosed (p : Set M) := h.symm.isClosed' +/-- If `p` and `q` are topological complements and `q` is closed, then `p` is Hausdorff. -/ protected theorem IsTopCompl.t3Space [IsTopologicalAddGroup M] (h : IsTopCompl p q) (hq : IsClosed (q : Set M)) : T3Space p := by have : IsClosed ({0} : Set p) := by @@ -256,7 +322,7 @@ theorem ClosedComplemented.exists_isClosed_isCompl [T1Space p] (h : ClosedComple ∃ q : Submodule R M, IsClosed (q : Set M) ∧ IsCompl p q := Exists.elim h.exists_isTopCompl fun q hq => ⟨q, hq.isClosed', hq.isCompl⟩ -/-- An arbitrary choice of topological complement of a closed complemented submodule. -/ +/-- An arbitrary choice of topological complement of a topologically complemented submodule. -/ noncomputable def ClosedComplemented.complement (h : ClosedComplemented p) : Submodule R M := Classical.choose h.exists_isTopCompl From 6b4b15292aa05d1a54563fc6d2d30cbc5e50d394 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Mon, 27 Apr 2026 15:18:21 +0200 Subject: [PATCH 005/210] Move --- .../Topology/Algebra/Module/Complement.lean | 17 +++++++++++++- Mathlib/Topology/Algebra/Module/Equiv.lean | 22 ------------------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 5660b1605745d0..d0392923fc147d 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -7,6 +7,7 @@ Authors: Jan-David Salchow, Sébastien Gouëzel, Jean Lo, Yury Kudryashov, Fréd module public import Mathlib.Topology.Algebra.Module.LinearMap +public import Mathlib.Topology.Algebra.Module.Equiv /-! # Topological complements of submodules @@ -61,7 +62,7 @@ There is still a significant part of the algebraic API which should be ported to topological setting. Notably, we should: * show that `Submodule.prodEquivOfIsCompl` is an homeomorphism if and only if the two subspaces are topological complements, and bundle it as a `ContinuousLinearEquiv` when - this is the case. + this is the case. (See the existing `ClosedComplemented.exists_submodule_equiv_prod`). * show that `Submodule.quotientEquivOfIsCompl` is an homeomorphism if and only if the two subspaces are topological complements, and bundle it as a `ContinuousLinearEquiv` when this is the case. @@ -359,6 +360,20 @@ theorem _root_.ContinuousLinearMap.closedComplemented_ker_of_rightInverse [Conti f₁.ker.ClosedComplemented := f₂.isTopCompl_range_ker_of_leftInverse f₁ h.leftInverse |>.symm.closedComplemented +/-- If `p` is a closed complemented submodule, +then there exists a submodule `q` and a continuous linear equivalence `M ≃L[R] (p × q)` such that +`e (x : p) = (x, 0)`, `e (y : q) = (0, y)`, and `e.symm x = x.1 + x.2`. + +In fact, the properties of `e` imply the properties of `e.symm` and vice versa, +but we provide both for convenience. -/ +lemma ClosedComplemented.exists_submodule_equiv_prod [IsTopologicalAddGroup M] + {p : Submodule R M} (hp : p.ClosedComplemented) : + ∃ (q : Submodule R M) (e : M ≃L[R] (p × q)), + (∀ x : p, e x = (x, 0)) ∧ (∀ y : q, e y = (0, y)) ∧ (∀ x, e.symm x = x.1 + x.2) := + let ⟨f, hf⟩ := hp + ⟨f.ker, .equivOfRightInverse f p.subtypeL hf, + fun _ ↦ by ext <;> simp [hf], fun _ ↦ by ext <;> simp, fun _ ↦ rfl⟩ + end ClosedComplemented end Submodule diff --git a/Mathlib/Topology/Algebra/Module/Equiv.lean b/Mathlib/Topology/Algebra/Module/Equiv.lean index af51d37ab81471..9e6aff85d43e39 100644 --- a/Mathlib/Topology/Algebra/Module/Equiv.lean +++ b/Mathlib/Topology/Algebra/Module/Equiv.lean @@ -1378,28 +1378,6 @@ end ContinuousLinearEquiv end map -namespace Submodule - -variable {R : Type*} [Ring R] {M : Type*} [TopologicalSpace M] [AddCommGroup M] [Module R M] - -open ContinuousLinearMap - -/-- If `p` is a closed complemented submodule, -then there exists a submodule `q` and a continuous linear equivalence `M ≃L[R] (p × q)` such that -`e (x : p) = (x, 0)`, `e (y : q) = (0, y)`, and `e.symm x = x.1 + x.2`. - -In fact, the properties of `e` imply the properties of `e.symm` and vice versa, -but we provide both for convenience. -/ -lemma ClosedComplemented.exists_submodule_equiv_prod [IsTopologicalAddGroup M] - {p : Submodule R M} (hp : p.ClosedComplemented) : - ∃ (q : Submodule R M) (e : M ≃L[R] (p × q)), - (∀ x : p, e x = (x, 0)) ∧ (∀ y : q, e y = (0, y)) ∧ (∀ x, e.symm x = x.1 + x.2) := - let ⟨f, hf⟩ := hp - ⟨f.ker, .equivOfRightInverse f p.subtypeL hf, - fun _ ↦ by ext <;> simp [hf], fun _ ↦ by ext <;> simp, fun _ ↦ rfl⟩ - -end Submodule - namespace MulOpposite variable (R : Type*) [Semiring R] [τR : TopologicalSpace R] [IsTopologicalSemiring R] From 0a4eb1d3e152cafb79b786d73b4e26e55a981c0f Mon Sep 17 00:00:00 2001 From: ADedecker Date: Mon, 27 Apr 2026 15:22:47 +0200 Subject: [PATCH 006/210] import --- Mathlib/Analysis/Normed/Module/Complemented.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/Mathlib/Analysis/Normed/Module/Complemented.lean b/Mathlib/Analysis/Normed/Module/Complemented.lean index 28188f66a96ca0..371c72e2d6c390 100644 --- a/Mathlib/Analysis/Normed/Module/Complemented.lean +++ b/Mathlib/Analysis/Normed/Module/Complemented.lean @@ -7,6 +7,7 @@ module public import Mathlib.Analysis.Normed.Operator.Banach public import Mathlib.Topology.Algebra.Module.FiniteDimension +public import Mathlib.Topology.Algebra.Module.Complement /-! # Complemented subspaces of normed vector spaces From a1eff4a16eede74ece4203c211e555a8d56c72f0 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Mon, 27 Apr 2026 16:35:52 +0200 Subject: [PATCH 007/210] feat: generalize Submodule.ClosedComplemented.of_quotient_finiteDimensional --- .../Analysis/Normed/Module/Complemented.lean | 19 -------- .../Algebra/Module/FiniteDimension.lean | 48 +++++++++++++++++-- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/Mathlib/Analysis/Normed/Module/Complemented.lean b/Mathlib/Analysis/Normed/Module/Complemented.lean index 371c72e2d6c390..d2ddb2602a73aa 100644 --- a/Mathlib/Analysis/Normed/Module/Complemented.lean +++ b/Mathlib/Analysis/Normed/Module/Complemented.lean @@ -35,19 +35,6 @@ open LinearMap (ker range) namespace ContinuousLinearMap -section - -variable [CompleteSpace 𝕜] - -theorem ker_closedComplemented_of_finiteDimensional_range (f : E →L[𝕜] F) - [FiniteDimensional 𝕜 f.range] : f.ker.ClosedComplemented := by - set f' : E →L[𝕜] f.range := f.codRestrict _ (LinearMap.mem_range_self (f : E →ₗ[𝕜] F)) - rcases f'.exists_right_inverse_of_surjective (f : E →ₗ[𝕜] F).range_rangeRestrict with ⟨g, hg⟩ - simpa only [f', ker_codRestrict] - using f'.closedComplemented_ker_of_rightInverse g (ContinuousLinearMap.ext_iff.1 hg) - -end - variable [CompleteSpace E] [CompleteSpace (F × G)] /-- If `f : E →L[R] F` and `g : E →L[R] G` are two surjective linear maps and @@ -127,10 +114,4 @@ theorem closedComplemented_iff_isClosed_exists_isClosed_isCompl : ⟨fun h => ⟨h.isClosed, h.exists_isClosed_isCompl⟩, fun ⟨hp, ⟨_, hq, hpq⟩⟩ => .of_isCompl_isClosed hpq hp hq⟩ -theorem ClosedComplemented.of_quotient_finiteDimensional [CompleteSpace 𝕜] - [FiniteDimensional 𝕜 (E ⧸ p)] (hp : IsClosed (p : Set E)) : p.ClosedComplemented := by - obtain ⟨q, hq⟩ : ∃ q, IsCompl p q := p.exists_isCompl - haveI : FiniteDimensional 𝕜 q := (p.quotientEquivOfIsCompl q hq).finiteDimensional - exact .of_isCompl_isClosed hq hp q.closed_of_finiteDimensional - end Submodule diff --git a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean index 1834c47ccb13bf..9513b4d07892ef 100644 --- a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean +++ b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean @@ -14,6 +14,7 @@ public import Mathlib.RingTheory.LocalRing.Basic public import Mathlib.Topology.Algebra.Module.Determinant public import Mathlib.Topology.Algebra.Module.ModuleTopology public import Mathlib.Topology.Algebra.Module.Simple +public import Mathlib.Topology.Algebra.Module.Complement public import Mathlib.Topology.Algebra.SeparationQuotient.FiniteDimensional /-! @@ -525,7 +526,7 @@ end IsUniformAddGroup variable {𝕜 E F : Type*} [NontriviallyNormedField 𝕜] [CompleteSpace 𝕜] [AddCommGroup E] [TopologicalSpace E] [IsTopologicalAddGroup E] [Module 𝕜 E] [ContinuousSMul 𝕜 E] - [AddCommGroup F] [TopologicalSpace F] [T2Space F] [IsTopologicalAddGroup F] [Module 𝕜 F] + [AddCommGroup F] [TopologicalSpace F] [IsTopologicalAddGroup F] [Module 𝕜 F] [ContinuousSMul 𝕜 F] /-- A finite-dimensional subspace is closed. -/ @@ -537,8 +538,8 @@ theorem Submodule.closed_of_finiteDimensional s.complete_of_finiteDimensional.isClosed /-- An injective linear map with finite-dimensional domain is a closed embedding. -/ -theorem LinearMap.isClosedEmbedding_of_injective [T2Space E] [FiniteDimensional 𝕜 E] {f : E →ₗ[𝕜] F} - (hf : LinearMap.ker f = ⊥) : IsClosedEmbedding f := +theorem LinearMap.isClosedEmbedding_of_injective [T2Space E] [FiniteDimensional 𝕜 E] [T2Space F] + {f : E →ₗ[𝕜] F} (hf : LinearMap.ker f = ⊥) : IsClosedEmbedding f := let g := LinearEquiv.ofInjective f (LinearMap.ker_eq_bot.mp hf) { IsEmbedding.subtypeVal.comp g.toContinuousLinearEquiv.toHomeomorph.isEmbedding with isClosed_range := by @@ -556,7 +557,7 @@ theorem isClosedMap_smul_left [T2Space E] (c : E) : IsClosedMap fun x : 𝕜 => exact isClosedMap_const · exact (isClosedEmbedding_smul_left hc).isClosedMap -theorem ContinuousLinearMap.exists_right_inverse_of_surjective [FiniteDimensional 𝕜 F] +theorem ContinuousLinearMap.exists_right_inverse_of_surjective [T2Space F] [FiniteDimensional 𝕜 F] (f : E →L[𝕜] F) (hf : f.range = ⊤) : ∃ g : F →L[𝕜] E, f.comp g = ContinuousLinearMap.id 𝕜 F := let ⟨g, hg⟩ := (f : E →ₗ[𝕜] F).exists_rightInverse_of_surjective hf @@ -669,3 +670,42 @@ theorem HasCompactMulSupport.eq_one_or_finiteDimensional {X : Type*} [Topologica HasCompactSupport.eq_zero_or_finiteDimensional 𝕜 (X := Additive X) hf h'f end Riesz + +section Compl + +open Submodule + +/-- If `p` is a closed subspace with finite codimension, then any algebraic complement `q` to `p` +is a topological complement. -/ +theorem IsCompl.isTopCompl_of_quotient_finiteDimensional {p q : Submodule 𝕜 E} + (h : IsCompl p q) (hp : IsClosed (p : Set E)) [FiniteDimensional 𝕜 (E ⧸ p)] : + IsTopCompl p q := by + let mkQ : E →L[𝕜] E ⧸ p := ⟨p.mkQ, continuous_quot_mk⟩ -- I can't believe we don't have this... + let φ : E ⧸ p →L[𝕜] q := (p.quotientEquivOfIsCompl q h).toLinearMap.toContinuousLinearMap + have := (φ ∘L mkQ).isTopCompl_of_proj fun x ↦ by simp [mkQ, φ] + simpa [φ, mkQ] using this.symm + +/-- Assume that `p q : Submodule 𝕜 E` are algebraic complements. If `p` is closed and `q` +has finite dimension, then they are in fact topological complements. + +Note that this theorem is not useful at all if you start from the finite dimensional subspace `q`, +because building a closed complement requires the Hahn-Banach theorem (and you don't get control +over what the complement is). See `Submodule.ClosedComplemented.of_finiteDimensional`. -/ +theorem IsCompl.isTopCompl_of_isClosed_of_finiteDimensional {p q : Submodule 𝕜 E} + (h : IsCompl p q) (hp : IsClosed (p : Set E)) [hq : FiniteDimensional 𝕜 q] : + IsTopCompl p q := by + suffices FiniteDimensional 𝕜 (E ⧸ p) from h.isTopCompl_of_quotient_finiteDimensional hp + exact (p.quotientEquivOfIsCompl q h).symm.finiteDimensional + +theorem Submodule.ClosedComplemented.of_quotient_finiteDimensional {p : Submodule 𝕜 E} + (hp : IsClosed (p : Set E)) [hq : FiniteDimensional 𝕜 (E ⧸ p)] : p.ClosedComplemented := by + obtain ⟨q, hq⟩ : ∃ q, IsCompl p q := p.exists_isCompl + exact hq.isTopCompl_of_quotient_finiteDimensional hp |>.closedComplemented + +omit [IsTopologicalAddGroup F] [ContinuousSMul 𝕜 F] in +theorem ContinuousLinearMap.ker_closedComplemented_of_finiteDimensional_range [T2Space F] + (f : E →L[𝕜] F) [FiniteDimensional 𝕜 f.range] : f.ker.ClosedComplemented := by + suffices FiniteDimensional 𝕜 (E ⧸ f.ker) from .of_quotient_finiteDimensional f.isClosed_ker + exact f.toLinearMap.quotKerEquivRange.symm.finiteDimensional + +end Compl From e6b86367dc698566055f488d4c74c6dfc62a772b Mon Sep 17 00:00:00 2001 From: ADedecker Date: Mon, 27 Apr 2026 16:37:30 +0200 Subject: [PATCH 008/210] Undo deprecation --- Mathlib/Topology/Algebra/Module/Complement.lean | 1 - 1 file changed, 1 deletion(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index d0392923fc147d..34bbcec67c9e2a 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -318,7 +318,6 @@ theorem closedComplemented_iff_exists_isTopCompl : ClosedComplemented p ↔ ∃ q, IsTopCompl p q := ⟨ClosedComplemented.exists_isTopCompl, fun H ↦ H.elim fun _ hq ↦ hq.closedComplemented⟩ -@[deprecated ClosedComplemented.exists_isTopCompl (since := "2026-04-27")] theorem ClosedComplemented.exists_isClosed_isCompl [T1Space p] (h : ClosedComplemented p) : ∃ q : Submodule R M, IsClosed (q : Set M) ∧ IsCompl p q := Exists.elim h.exists_isTopCompl fun q hq => ⟨q, hq.isClosed', hq.isCompl⟩ From f8a06cd67eee852b22513c22cc6940b20cb2f655 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Mon, 27 Apr 2026 16:48:02 +0200 Subject: [PATCH 009/210] fixes --- Mathlib/Analysis/Normed/Module/ContinuousInverse.lean | 2 ++ Mathlib/Analysis/Normed/Module/HahnBanach.lean | 1 + 2 files changed, 3 insertions(+) diff --git a/Mathlib/Analysis/Normed/Module/ContinuousInverse.lean b/Mathlib/Analysis/Normed/Module/ContinuousInverse.lean index 08fe0ab7ababd0..eaf79f0697f91f 100644 --- a/Mathlib/Analysis/Normed/Module/ContinuousInverse.lean +++ b/Mathlib/Analysis/Normed/Module/ContinuousInverse.lean @@ -7,6 +7,7 @@ module public import Mathlib.Analysis.Normed.Operator.Banach public import Mathlib.Topology.Algebra.Module.FiniteDimension +public import Mathlib.Topology.Algebra.Module.Complement /-! # Continuous linear maps with a continuous left/right inverse @@ -232,6 +233,7 @@ def complement (h : f.HasLeftInverse) : Submodule R F := lemma isClosed_complement (h : f.HasLeftInverse) : IsClosed (X := F) h.complement := h.closedComplemented_range.isClosed_complement +omit [T1Space F] in lemma isCompl_complement (h : f.HasLeftInverse) : IsCompl f.range h.complement := h.closedComplemented_range.isCompl_complement diff --git a/Mathlib/Analysis/Normed/Module/HahnBanach.lean b/Mathlib/Analysis/Normed/Module/HahnBanach.lean index e5a89f9bbbb483..6da6f8d8dbb9f7 100644 --- a/Mathlib/Analysis/Normed/Module/HahnBanach.lean +++ b/Mathlib/Analysis/Normed/Module/HahnBanach.lean @@ -8,6 +8,7 @@ module public import Mathlib.Analysis.Convex.Cone.Extension public import Mathlib.Analysis.Normed.Module.RCLike.Extend public import Mathlib.Analysis.RCLike.Lemmas +public import Mathlib.Topology.Algebra.Module.Complement /-! # Extension Hahn-Banach theorem From 6f45181ff3daa68f569b878b7ccd9030599d0e80 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Mon, 27 Apr 2026 17:31:45 +0200 Subject: [PATCH 010/210] fix simps --- Mathlib/Topology/Algebra/Module/Complement.lean | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 34bbcec67c9e2a..58415203a3788e 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -160,7 +160,6 @@ theorem IsTopCompl.projectionOnto_apply_left (h : IsTopCompl p q) (x : p) : h.projectionOnto x = x := linearProjOfIsCompl_apply_left h.isCompl x -@[simp] theorem IsTopCompl.range_projectionOnto (h : IsTopCompl p q) : h.projectionOnto.range = ⊤ := linearProjOfIsCompl_range h.isCompl @@ -224,7 +223,6 @@ theorem IsTopCompl.projection_apply_left (h : IsTopCompl p q) (x : p) : h.projection x = x := IsCompl.projection_apply_left h.isCompl x -@[simp] theorem IsTopCompl.range_projection (h : IsTopCompl p q) : h.projection.range = p := IsCompl.projection_range h.isCompl @@ -242,6 +240,10 @@ theorem IsTopCompl.projection_apply_right (h : IsTopCompl p q) (x : q) : h.projection x = 0 := h.projection_apply_eq_zero_of_mem_right x.2 +theorem IsTopCompl.ker_projection (h : IsTopCompl p q) : + ker (h.projection : M →ₗ[R] M) = q := + IsCompl.projection_ker h.isCompl + @[simp] theorem IsTopCompl.projection_isIdempotentElem (h : IsTopCompl p q) : IsIdempotentElem h.projection := by From 1db9ab236c998f3071fc36a6f76dbf849c6a6a90 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Mon, 27 Apr 2026 22:35:45 +0200 Subject: [PATCH 011/210] dot notation --- .../Topology/Algebra/Module/Complement.lean | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 58415203a3788e..8169b5d4f518f3 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -73,7 +73,7 @@ topological setting. Notably, we should: @[expose] public section open LinearMap (ker range) -open Topology ContinuousLinearMap Function +open Topology ContinuousLinearMap Function Submodule namespace Submodule @@ -86,7 +86,7 @@ open ContinuousLinearMap the projection on `p` parallel to `q` is continuous. -/ structure IsTopCompl (p q : Submodule R M) : Prop where isCompl : IsCompl p q - continuous_projection : Continuous (IsCompl.projection isCompl) + continuous_projection : Continuous (isCompl.projection) /-- A submodule `p` is called *complemented* if there exists a continuous projection `M →ₗ[R] p`. -/ def ClosedComplemented (p : Submodule R M) : Prop := @@ -96,14 +96,14 @@ variable {p q : Submodule R M} section IsTopCompl -theorem _root_.IsCompl.isTopCompl_iff (h : IsCompl p q) : - IsTopCompl p q ↔ Continuous (IsCompl.projection h) := +theorem IsCompl.isTopCompl_iff (h : IsCompl p q) : + IsTopCompl p q ↔ Continuous h.projection := ⟨IsTopCompl.continuous_projection, fun h' ↦ ⟨h, h'⟩⟩ protected theorem IsTopCompl.symm [ContinuousSub M] (h : IsTopCompl p q) : IsTopCompl q p where isCompl := h.isCompl.symm continuous_projection := by - rw [IsCompl.projection_eq_id_sub_projection h.isCompl] + rw [h.isCompl.projection_eq_id_sub_projection] exact continuous_id.sub h.continuous_projection theorem _root_.IsIdempotentElem.isTopCompl {f : M →L[R] M} (hf : IsIdempotentElem f) : @@ -201,7 +201,7 @@ protected noncomputable def IsTopCompl.projection (h : IsTopCompl p q) : M →L[ @[simp] theorem IsTopCompl.projection_toLinearMap (h : IsTopCompl p q) : - (h.projection : M →ₗ[R] M) = IsCompl.projection h.isCompl := + (h.projection : M →ₗ[R] M) = h.isCompl.projection := rfl theorem IsTopCompl.projection_apply (h : IsTopCompl p q) (x : M) : @@ -221,16 +221,16 @@ theorem IsTopCompl.projection_apply_mem (h : IsTopCompl p q) (x : M) : @[simp] theorem IsTopCompl.projection_apply_left (h : IsTopCompl p q) (x : p) : h.projection x = x := - IsCompl.projection_apply_left h.isCompl x + h.isCompl.projection_apply_left x theorem IsTopCompl.range_projection (h : IsTopCompl p q) : h.projection.range = p := - IsCompl.projection_range h.isCompl + h.isCompl.projection_range @[simp] theorem IsTopCompl.projection_apply_eq_zero_iff (h : IsTopCompl p q) {x : M} : h.projection x = 0 ↔ x ∈ q := - IsCompl.projection_apply_eq_zero_iff h.isCompl + h.isCompl.projection_apply_eq_zero_iff alias ⟨_, IsTopCompl.projection_apply_eq_zero_of_mem_right⟩ := IsTopCompl.projection_apply_eq_zero_iff @@ -242,7 +242,7 @@ theorem IsTopCompl.projection_apply_right (h : IsTopCompl p q) (x : q) : theorem IsTopCompl.ker_projection (h : IsTopCompl p q) : ker (h.projection : M →ₗ[R] M) = q := - IsCompl.projection_ker h.isCompl + h.isCompl.projection_ker @[simp] theorem IsTopCompl.projection_isIdempotentElem (h : IsTopCompl p q) : @@ -252,7 +252,7 @@ theorem IsTopCompl.projection_isIdempotentElem (h : IsTopCompl p q) : theorem IsTopCompl.projection_add_projection_eq_self [ContinuousSub M] (h : IsTopCompl p q) (x : M) : h.projection x + h.symm.projection x = x := - IsCompl.projection_add_projection_eq_self h.isCompl x + h.isCompl.projection_add_projection_eq_self x theorem IsTopCompl.projection_add_projection_eq_id [IsTopologicalAddGroup M] (h : IsTopCompl p q) : h.projection + h.symm.projection = .id R M := by @@ -271,7 +271,7 @@ lemma IsTopCompl.projection_eq_id_sub_projection [IsTopologicalAddGroup M] (h : /-- The projection to `p` along `q` of `x` equals `x` if and only if `x ∈ p`. -/ @[simp] lemma IsTopCompl.projection_eq_self_iff [ContinuousSub M] (h : IsTopCompl p q) (x : M) : h.projection x = x ↔ x ∈ p := - IsCompl.projection_eq_self_iff h.isCompl x + h.isCompl.projection_eq_self_iff x end projection From 46029b297b0f9b2d02c0e2a28913b89966e5ed15 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 29 Apr 2026 14:39:15 +0200 Subject: [PATCH 012/210] Comment and namespace fix --- Mathlib/Topology/Algebra/Module/Complement.lean | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 8169b5d4f518f3..28979e2c579395 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -106,7 +106,8 @@ protected theorem IsTopCompl.symm [ContinuousSub M] (h : IsTopCompl p q) : IsTop rw [h.isCompl.projection_eq_id_sub_projection] exact continuous_id.sub h.continuous_projection -theorem _root_.IsIdempotentElem.isTopCompl {f : M →L[R] M} (hf : IsIdempotentElem f) : +theorem _root_.ContinuousLinearMap.IsIdempotentElem.isTopCompl {f : M →L[R] M} + (hf : IsIdempotentElem f) : IsTopCompl f.range f.ker := by rw [← isIdempotentElem_toLinearMap_iff] at hf refine ⟨LinearMap.IsIdempotentElem.isCompl hf, ?_⟩ @@ -291,7 +292,6 @@ protected theorem IsTopCompl.isClosed [T1Space q] [ContinuousSub M] (h : IsTopCo IsClosed (p : Set M) := h.symm.isClosed' -/-- If `p` and `q` are topological complements and `q` is closed, then `p` is Hausdorff. -/ protected theorem IsTopCompl.t3Space [IsTopologicalAddGroup M] (h : IsTopCompl p q) (hq : IsClosed (q : Set M)) : T3Space p := by have : IsClosed ({0} : Set p) := by @@ -301,6 +301,7 @@ protected theorem IsTopCompl.t3Space [IsTopologicalAddGroup M] (h : IsTopCompl p rw [RegularSpace.t3Space_iff_t0Space] infer_instance +/-- If `p` and `q` are topological complements and `q` is closed, then `p` is Hausdorff. -/ protected theorem IsTopCompl.t2Space [IsTopologicalAddGroup M] (h : IsTopCompl p q) (hq : IsClosed (q : Set M)) : T2Space p := have := h.t3Space hq From 18196c00d18416958249944428f94e299f95549c Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 29 Apr 2026 14:44:58 +0200 Subject: [PATCH 013/210] copyright --- Mathlib/Topology/Algebra/Module/Complement.lean | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 28979e2c579395..dda9a37d5ff88e 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -1,8 +1,7 @@ /- -Copyright (c) 2019 Sébastien Gouëzel. All rights reserved. +Copyright (c) 2026 Anatole Dedecker. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Jan-David Salchow, Sébastien Gouëzel, Jean Lo, Yury Kudryashov, Frédéric Dupuis, - Heather Macbeth, Anatole Dedecker +Authors: Anatole Dedecker -/ module From fab83775096b99c2fbae8831084697ccc8642187 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 29 Apr 2026 14:49:39 +0200 Subject: [PATCH 014/210] switch idempotent --- Mathlib/LinearAlgebra/Projection.lean | 7 +++++-- Mathlib/Topology/Algebra/Module/Complement.lean | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Mathlib/LinearAlgebra/Projection.lean b/Mathlib/LinearAlgebra/Projection.lean index dfa0be311c6a10..3da8404bee2ec6 100644 --- a/Mathlib/LinearAlgebra/Projection.lean +++ b/Mathlib/LinearAlgebra/Projection.lean @@ -237,10 +237,13 @@ theorem linearProjOfIsCompl_isCompl_projection (h : IsCompl p q) (x : E) : /-- The linear projection onto a subspace along its complement is an idempotent. -/ @[simp] -theorem IsCompl.projection_isIdempotentElem (hpq : IsCompl p q) : +theorem IsCompl.isIdempotentElem_projection (hpq : IsCompl p q) : IsIdempotentElem hpq.projection := LinearMap.ext fun _ ↦ congr($(linearProjOfIsCompl_isCompl_projection hpq _)) +@[deprecated (since := "2026-04-29")] +alias IsCompl.projection_isIdempotentElem := IsCompl.isIdempotentElem_projection + theorem existsUnique_add_of_isCompl_prod (hc : IsCompl p q) (x : E) : ∃! u : p × q, (u.fst : E) + u.snd = x := (prodEquivOfIsCompl _ _ hc).toEquiv.bijective.existsUnique _ @@ -629,7 +632,7 @@ onto its range along its kernel. -/ theorem isIdempotentElem_iff_eq_isCompl_projection_range_ker {T : E →ₗ[R] E} : IsIdempotentElem T ↔ ∃ (h : IsCompl (range T) (ker T)), T = h.projection := ⟨fun hT => ⟨hT.isProj_range.isCompl, hT.eq_isCompl_projection⟩, - fun ⟨hT, h⟩ => h.symm ▸ hT.projection_isIdempotentElem⟩ + fun ⟨hT, h⟩ => h.symm ▸ hT.isIdempotentElem_projection⟩ open LinearMap in /-- Given an idempotent linear operator `q`, diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index dda9a37d5ff88e..217edb8c86fdff 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -85,7 +85,7 @@ open ContinuousLinearMap the projection on `p` parallel to `q` is continuous. -/ structure IsTopCompl (p q : Submodule R M) : Prop where isCompl : IsCompl p q - continuous_projection : Continuous (isCompl.projection) + continuous_projection : Continuous isCompl.projection /-- A submodule `p` is called *complemented* if there exists a continuous projection `M →ₗ[R] p`. -/ def ClosedComplemented (p : Submodule R M) : Prop := @@ -245,7 +245,7 @@ theorem IsTopCompl.ker_projection (h : IsTopCompl p q) : h.isCompl.projection_ker @[simp] -theorem IsTopCompl.projection_isIdempotentElem (h : IsTopCompl p q) : +theorem IsTopCompl.isIdempotentElem_projection (h : IsTopCompl p q) : IsIdempotentElem h.projection := by simp [← isIdempotentElem_toLinearMap_iff] From 6722d7d779f36fdd6efc8527a247fb4f68fb7f25 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 29 Apr 2026 14:54:38 +0200 Subject: [PATCH 015/210] add characterization in terms of `linearProjOfIsCompl` --- Mathlib/Topology/Algebra/Module/Complement.lean | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 217edb8c86fdff..f7eb0f7e00291a 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -99,6 +99,11 @@ theorem IsCompl.isTopCompl_iff (h : IsCompl p q) : IsTopCompl p q ↔ Continuous h.projection := ⟨IsTopCompl.continuous_projection, fun h' ↦ ⟨h, h'⟩⟩ +theorem IsCompl.isTopCompl_iff_linearProjOfIsCompl (h : IsCompl p q) : + IsTopCompl p q ↔ Continuous (p.linearProjOfIsCompl q h) := by + rw [h.isTopCompl_iff, IsInducing.subtypeVal.continuous_iff] + rfl + protected theorem IsTopCompl.symm [ContinuousSub M] (h : IsTopCompl p q) : IsTopCompl q p where isCompl := h.isCompl.symm continuous_projection := by From ffce1a26576cceb7c7e53dc7dfafb0568387ed01 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 29 Apr 2026 14:56:47 +0200 Subject: [PATCH 016/210] switch "toLinearMap" --- Mathlib/Topology/Algebra/Module/Complement.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index f7eb0f7e00291a..428a293d83d8fe 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -156,7 +156,7 @@ protected noncomputable def IsTopCompl.projectionOnto (h : IsTopCompl p q) : M exact h.continuous_projection⟩ @[simp] -theorem IsTopCompl.projectionOnto_toLinearMap (h : IsTopCompl p q) : +theorem IsTopCompl.toLinearMap_projectionOnto (h : IsTopCompl p q) : (h.projectionOnto : M →ₗ[R] p) = p.linearProjOfIsCompl q h.isCompl := rfl @@ -205,7 +205,7 @@ protected noncomputable def IsTopCompl.projection (h : IsTopCompl p q) : M →L[ p.subtypeL ∘L h.projectionOnto @[simp] -theorem IsTopCompl.projection_toLinearMap (h : IsTopCompl p q) : +theorem IsTopCompl.toLinearMap_projection (h : IsTopCompl p q) : (h.projection : M →ₗ[R] M) = h.isCompl.projection := rfl From fe8246fa4502c5494aa68272bd33b6a8740d4422 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 29 Apr 2026 15:54:13 +0200 Subject: [PATCH 017/210] fix --- Mathlib/Analysis/InnerProductSpace/Symmetric.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Analysis/InnerProductSpace/Symmetric.lean b/Mathlib/Analysis/InnerProductSpace/Symmetric.lean index 7e1e1f9124a3e8..c0f26a3005dde5 100644 --- a/Mathlib/Analysis/InnerProductSpace/Symmetric.lean +++ b/Mathlib/Analysis/InnerProductSpace/Symmetric.lean @@ -305,7 +305,7 @@ open Submodule in theorem _root_.Submodule.IsCompl.projection_isSymmetricProjection_iff {U V : Submodule 𝕜 E} (hUV : IsCompl U V) : hUV.projection.IsSymmetricProjection ↔ U ⟂ V := by - simp [isSymmetricProjection_iff, hUV.projection_isSymmetric_iff, hUV.projection_isIdempotentElem] + simp [isSymmetricProjection_iff, hUV.projection_isSymmetric_iff, hUV.isIdempotentElem_projection] alias ⟨_, _root_.Submodule.IsCompl.projection_isSymmetricProjection_of_isOrtho⟩ := _root_.Submodule.IsCompl.projection_isSymmetricProjection_iff From 4df02c7a3bfa03e279d3081ebcd1be15de6877be Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 29 Apr 2026 15:55:33 +0200 Subject: [PATCH 018/210] simps --- Mathlib/Topology/Algebra/Module/Complement.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 428a293d83d8fe..9183d919698be5 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -165,6 +165,7 @@ theorem IsTopCompl.projectionOnto_apply_left (h : IsTopCompl p q) (x : p) : h.projectionOnto x = x := linearProjOfIsCompl_apply_left h.isCompl x +@[simp] theorem IsTopCompl.range_projectionOnto (h : IsTopCompl p q) : h.projectionOnto.range = ⊤ := linearProjOfIsCompl_range h.isCompl @@ -184,6 +185,7 @@ theorem IsTopCompl.projectionOnto_apply_right (h : IsTopCompl p q) (x : q) : h.projectionOnto x = 0 := h.projectionOnto_apply_eq_zero_of_mem_right x.2 +@[simp] theorem IsTopCompl.ker_projectionOnto (h : IsTopCompl p q) : ker (h.projectionOnto : M →ₗ[R] p) = q := linearProjOfIsCompl_ker h.isCompl @@ -228,6 +230,7 @@ theorem IsTopCompl.projection_apply_left (h : IsTopCompl p q) (x : p) : h.projection x = x := h.isCompl.projection_apply_left x +@[simp] theorem IsTopCompl.range_projection (h : IsTopCompl p q) : h.projection.range = p := h.isCompl.projection_range @@ -245,6 +248,7 @@ theorem IsTopCompl.projection_apply_right (h : IsTopCompl p q) (x : q) : h.projection x = 0 := h.projection_apply_eq_zero_of_mem_right x.2 +@[simp] theorem IsTopCompl.ker_projection (h : IsTopCompl p q) : ker (h.projection : M →ₗ[R] M) = q := h.isCompl.projection_ker From cd5f7f7bb19db01adb0773e67aa8162d2490edf9 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 29 Apr 2026 15:56:44 +0200 Subject: [PATCH 019/210] parallel -> along --- Mathlib/Topology/Algebra/Module/Complement.lean | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 9183d919698be5..a5fed60ed4d94e 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -25,15 +25,15 @@ change to something less misleading. ## Main definitions * `Submodule.IsTopCompl`: we say that two submodules are *topological complements* if they are - algebraic complements and the projection on `p` parallel to `q` is continuous. This is equivalent + algebraic complements and the projection on `p` along `q` is continuous. This is equivalent to the definition given above. * `Submodule.ClosedComplemented`: we say that a submodule is (topologically) *complemented* if there exists a continuous projection `M →ₗ[R] p`. * `Submodule.IsTopCompl.projectionOnto`: if `h : IsTopCompl p q`, `h.projectionOnto` is the - continuous linear projection `M →L[R] p` parallel to `q`. This is the continuous version of + continuous linear projection `M →L[R] p` along `q`. This is the continuous version of `Submodule.linearProjOfIsCompl`. * `Submodule.IsTopCompl.projection`: if `h : IsTopCompl p q`, `h.projection` is the continuous - linear projection `M →L[R] M` onto `p` parallel to `q`. This is the continuous version of + linear projection `M →L[R] M` onto `p` along `q`. This is the continuous version of `Submodule.IsCompl.projection`. * `Submodule.ClosedComplemented.complement`: an arbitrary topological complement of a topologically complemented submodule. @@ -48,7 +48,7 @@ change to something less misleading. ## Implementation details In the definition of `Submodule.IsTopCompl`, we choose to ask for the continuity of the projection -on the left submdule parallel to the right one, because it is a simpler map to work with than the +on the left submdule along the right one, because it is a simpler map to work with than the map `M ≃ p × q`. Because the condition is symmetric, a lot of lemmas could have a left and a right variation. @@ -82,7 +82,7 @@ variable {R : Type*} [Ring R] {M N : Type*} [TopologicalSpace M] [TopologicalSpa open ContinuousLinearMap /-- Two submodules `p` and `q` are *topological complements* if they are algebraic complements and -the projection on `p` parallel to `q` is continuous. -/ +the projection on `p` along `q` is continuous. -/ structure IsTopCompl (p q : Submodule R M) : Prop where isCompl : IsCompl p q continuous_projection : Continuous isCompl.projection @@ -147,7 +147,7 @@ theorem _root_.ContinuousLinearMap.isTopCompl_of_proj {f : M →L[R] p} (hf : section projectionOnto /-- If `h : IsTopCompl p q`, `h.projectionOnto` is the continuous linear projection `M →L[R] p` -parallel to `q`. This is the continuous version of `Submodule.linearProjOfIsCompl`. +along `q`. This is the continuous version of `Submodule.linearProjOfIsCompl`. See also `Submodule.IsTopCompl.projection` for the same projection as an element of `M →L[R] M`. -/ protected noncomputable def IsTopCompl.projectionOnto (h : IsTopCompl p q) : M →L[R] p := @@ -199,7 +199,7 @@ end projectionOnto section projection /-- If `h : IsTopCompl p q`, `h.projection` is the continuous linear projection `M →L[R] M` onto -`p` parallel to `q`. This is the continuous version of `Submodule.IsCompl.projection`. +`p` along `q`. This is the continuous version of `Submodule.IsCompl.projection`. See also `Submodule.IsTopCompl.projectionOnto` for the same projection as an element of `M →L[R] p`. -/ From 0db8c342b7369e2d49e48e56c5d01a4d64cee7c4 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 29 Apr 2026 16:00:15 +0200 Subject: [PATCH 020/210] golf --- Mathlib/Topology/Algebra/Module/Complement.lean | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index a5fed60ed4d94e..c2fa4f9d6c7f13 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -104,6 +104,10 @@ theorem IsCompl.isTopCompl_iff_linearProjOfIsCompl (h : IsCompl p q) : rw [h.isTopCompl_iff, IsInducing.subtypeVal.continuous_iff] rfl +theorem IsTopCompl.continuous_linearProjOfIsCompl (h : IsTopCompl p q) : + Continuous (p.linearProjOfIsCompl q h.isCompl) := + h.isCompl.isTopCompl_iff_linearProjOfIsCompl.mp h + protected theorem IsTopCompl.symm [ContinuousSub M] (h : IsTopCompl p q) : IsTopCompl q p where isCompl := h.isCompl.symm continuous_projection := by @@ -151,9 +155,7 @@ along `q`. This is the continuous version of `Submodule.linearProjOfIsCompl`. See also `Submodule.IsTopCompl.projection` for the same projection as an element of `M →L[R] M`. -/ protected noncomputable def IsTopCompl.projectionOnto (h : IsTopCompl p q) : M →L[R] p := - ⟨p.linearProjOfIsCompl q h.isCompl, by - rw [IsInducing.subtypeVal.continuous_iff] - exact h.continuous_projection⟩ + ⟨p.linearProjOfIsCompl q h.isCompl, h.continuous_linearProjOfIsCompl⟩ @[simp] theorem IsTopCompl.toLinearMap_projectionOnto (h : IsTopCompl p q) : From a5d6d7e38d1fb719437dd3d5e5bb84885ec2b9f3 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 29 Apr 2026 16:02:07 +0200 Subject: [PATCH 021/210] reorder --- Mathlib/LinearAlgebra/Projection.lean | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mathlib/LinearAlgebra/Projection.lean b/Mathlib/LinearAlgebra/Projection.lean index 3da8404bee2ec6..8ac46befc9c462 100644 --- a/Mathlib/LinearAlgebra/Projection.lean +++ b/Mathlib/LinearAlgebra/Projection.lean @@ -200,14 +200,14 @@ theorem IsCompl.projection_apply_eq_zero_iff (hpq : IsCompl p q) {x : E} : alias ⟨_, linearProjOfIsCompl_apply_of_mem_right⟩ := linearProjOfIsCompl_apply_eq_zero_iff +alias ⟨_, IsCompl.projection_apply_of_mem_right⟩ := + IsCompl.projection_apply_eq_zero_iff + @[deprecated linearProjOfIsCompl_apply_of_mem_right (since := "2026-04-27")] theorem linearProjOfIsCompl_apply_right' (h : IsCompl p q) (x : E) (hx : x ∈ q) : linearProjOfIsCompl p q h x = 0 := linearProjOfIsCompl_apply_of_mem_right h hx -alias ⟨_, IsCompl.projection_apply_of_mem_right⟩ := - IsCompl.projection_apply_eq_zero_iff - @[simp] theorem linearProjOfIsCompl_apply_right (h : IsCompl p q) (x : q) : linearProjOfIsCompl p q h x = 0 := From 13882c5d5fd0c04d30d916ed4e98edec1a679584 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 29 Apr 2026 16:48:59 +0200 Subject: [PATCH 022/210] Remove useless simp --- Mathlib/Topology/Algebra/Module/Complement.lean | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index c2fa4f9d6c7f13..485e9eb2f21dc3 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -167,7 +167,6 @@ theorem IsTopCompl.projectionOnto_apply_left (h : IsTopCompl p q) (x : p) : h.projectionOnto x = x := linearProjOfIsCompl_apply_left h.isCompl x -@[simp] theorem IsTopCompl.range_projectionOnto (h : IsTopCompl p q) : h.projectionOnto.range = ⊤ := linearProjOfIsCompl_range h.isCompl @@ -187,7 +186,6 @@ theorem IsTopCompl.projectionOnto_apply_right (h : IsTopCompl p q) (x : q) : h.projectionOnto x = 0 := h.projectionOnto_apply_eq_zero_of_mem_right x.2 -@[simp] theorem IsTopCompl.ker_projectionOnto (h : IsTopCompl p q) : ker (h.projectionOnto : M →ₗ[R] p) = q := linearProjOfIsCompl_ker h.isCompl @@ -232,7 +230,6 @@ theorem IsTopCompl.projection_apply_left (h : IsTopCompl p q) (x : p) : h.projection x = x := h.isCompl.projection_apply_left x -@[simp] theorem IsTopCompl.range_projection (h : IsTopCompl p q) : h.projection.range = p := h.isCompl.projection_range @@ -250,7 +247,6 @@ theorem IsTopCompl.projection_apply_right (h : IsTopCompl p q) (x : q) : h.projection x = 0 := h.projection_apply_eq_zero_of_mem_right x.2 -@[simp] theorem IsTopCompl.ker_projection (h : IsTopCompl p q) : ker (h.projection : M →ₗ[R] M) = q := h.isCompl.projection_ker From 0a29e324dd5fda90fa7cc0b141d483876c9e143c Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Thu, 30 Apr 2026 21:35:53 +0200 Subject: [PATCH 023/210] Apply suggestions from code review Co-authored-by: Monica Omar <23701951+themathqueen@users.noreply.github.com> --- Mathlib/LinearAlgebra/Projection.lean | 10 +++---- .../Topology/Algebra/Module/Complement.lean | 28 +++++++++++-------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/Mathlib/LinearAlgebra/Projection.lean b/Mathlib/LinearAlgebra/Projection.lean index 8ac46befc9c462..a2ee36737004b2 100644 --- a/Mathlib/LinearAlgebra/Projection.lean +++ b/Mathlib/LinearAlgebra/Projection.lean @@ -260,18 +260,16 @@ theorem IsCompl.projection_add_projection_eq_self (hpq : IsCompl p q) (x : E) : exact (prodEquivOfIsCompl _ _ hpq).apply_symm_apply x theorem IsCompl.projection_add_projection_eq_id (hpq : IsCompl p q) : - hpq.projection + hpq.symm.projection = .id := by - ext - apply IsCompl.projection_add_projection_eq_self hpq + hpq.projection + hpq.symm.projection = .id := + LinearMap.ext hpq.projection_add_projection_eq_self lemma IsCompl.projection_eq_self_sub_projection (hpq : IsCompl p q) (x : E) : hpq.symm.projection x = x - hpq.projection x := by rw [eq_sub_iff_add_eq, projection_add_projection_eq_self] lemma IsCompl.projection_eq_id_sub_projection (hpq : IsCompl p q) : - hpq.symm.projection = .id - hpq.projection := by - ext - apply IsCompl.projection_eq_self_sub_projection hpq + hpq.symm.projection = .id - hpq.projection := + LinearMap.ext hpq.projection_eq_self_sub_projection /-- The projection to `p` along `q` of `x` equals `x` if and only if `x ∈ p`. -/ @[simp] lemma IsCompl.projection_eq_self_iff (hpq : IsCompl p q) (x : E) : diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 485e9eb2f21dc3..b858758120d0d7 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -114,13 +114,11 @@ protected theorem IsTopCompl.symm [ContinuousSub M] (h : IsTopCompl p q) : IsTop rw [h.isCompl.projection_eq_id_sub_projection] exact continuous_id.sub h.continuous_projection +open LinearMap in theorem _root_.ContinuousLinearMap.IsIdempotentElem.isTopCompl {f : M →L[R] M} - (hf : IsIdempotentElem f) : - IsTopCompl f.range f.ker := by - rw [← isIdempotentElem_toLinearMap_iff] at hf - refine ⟨LinearMap.IsIdempotentElem.isCompl hf, ?_⟩ - rw [← LinearMap.IsIdempotentElem.eq_isCompl_projection hf] - exact f.continuous + (hf : IsIdempotentElem f) : IsTopCompl f.range f.ker where + isCompl := hf.toLinearMap.isCompl + continuous_projection := hf.toLinearMap.eq_isCompl_projection ▸ f.continuous theorem isTopCompl_bot_top : IsTopCompl (⊥ : Submodule R M) ⊤ := by @@ -262,24 +260,30 @@ theorem IsTopCompl.projection_add_projection_eq_self [ContinuousSub M] h.isCompl.projection_add_projection_eq_self x theorem IsTopCompl.projection_add_projection_eq_id [IsTopologicalAddGroup M] (h : IsTopCompl p q) : - h.projection + h.symm.projection = .id R M := by - ext - apply h.projection_add_projection_eq_self + h.projection + h.symm.projection = .id R M := + ContinuousLinearMap.ext h.projection_add_projection_eq_self lemma IsTopCompl.projection_eq_self_sub_projection [ContinuousSub M] (h : IsTopCompl p q) (x : M) : h.symm.projection x = x - h.projection x := by rw [eq_sub_iff_add_eq, projection_add_projection_eq_self] lemma IsTopCompl.projection_eq_id_sub_projection [IsTopologicalAddGroup M] (h : IsTopCompl p q) : - h.symm.projection = .id R M - h.projection := by - ext - apply h.projection_eq_self_sub_projection + h.symm.projection = .id R M - h.projection := + ContinuousLinearMap.ext h.projection_eq_self_sub_projection /-- The projection to `p` along `q` of `x` equals `x` if and only if `x ∈ p`. -/ @[simp] lemma IsTopCompl.projection_eq_self_iff [ContinuousSub M] (h : IsTopCompl p q) (x : M) : h.projection x = x ↔ x ∈ p := h.isCompl.projection_eq_self_iff x +theorem _root_.ContinuousLinearMap.IsIdempotentElem.eq_isTopCompl_projection + {f : M →L[R] M} (hf : IsIdempotentElem f) : f = hf.isTopCompl.projection := + coe_inj.mp <| LinearMap.IsIdempotentElem.eq_isCompl_projection hf.toLinearMap + +theorem _root_.ContinuousLinearMap.isIdempotentElem_iff_eq_isTopCompl_projection_range_ker + {f : M →L[R] M} : IsIdempotentElem f ↔ ∃ h : IsTopCompl f.range f.ker, f = h.projection := + ⟨fun h ↦ ⟨_, h.eq_isTopCompl_projection⟩, fun ⟨hf, h⟩ ↦ h.symm ▸ hf.isIdempotentElem_projection⟩ + end projection section closed_hausdorff From 988cf9027a5fd108ef6048e0721f01926918bca2 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Sat, 2 May 2026 23:55:28 +0200 Subject: [PATCH 024/210] literature --- Mathlib/Topology/Algebra/Module/Complement.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index b858758120d0d7..c2e12f92f9f656 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -16,7 +16,7 @@ Let `M` be a topological `R`-module. Two submodules `p, q` of `M` are said to be algebraic isomorphism `M ≃ p × q` is an homeomorphism. Not all submodules of `M` admit such a topological complements (even if they admit algebraic -complements). In the litterature, such a submodule is called *topologically complemented* +complements). In the literature, such a submodule is called *topologically complemented* or *direct*. One may also find the terminology *closed complemented* because, in a Banach space, a closed algebraic complement is automatically a topological complement. This is the terminology we use for now (`Submodule.ClosedComplemented`), but we should eventually From b50e9268360bca38b5339dc4f78760866c6e9a3c Mon Sep 17 00:00:00 2001 From: ADedecker Date: Sun, 3 May 2026 00:08:17 +0200 Subject: [PATCH 025/210] .ker --- Mathlib/Topology/Algebra/Module/Complement.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index c2e12f92f9f656..a5234b4eec19f2 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -185,7 +185,7 @@ theorem IsTopCompl.projectionOnto_apply_right (h : IsTopCompl p q) (x : q) : h.projectionOnto_apply_eq_zero_of_mem_right x.2 theorem IsTopCompl.ker_projectionOnto (h : IsTopCompl p q) : - ker (h.projectionOnto : M →ₗ[R] p) = q := + h.projectionOnto.ker = q := linearProjOfIsCompl_ker h.isCompl theorem IsTopCompl.isQuotientMap_projectionOnto (h : IsTopCompl p q) : @@ -246,7 +246,7 @@ theorem IsTopCompl.projection_apply_right (h : IsTopCompl p q) (x : q) : h.projection_apply_eq_zero_of_mem_right x.2 theorem IsTopCompl.ker_projection (h : IsTopCompl p q) : - ker (h.projection : M →ₗ[R] M) = q := + h.projection.ker = q := h.isCompl.projection_ker @[simp] From 93e704ea1d27f2ab403c8af6582c24e5c59cf128 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Mon, 4 May 2026 13:39:06 +0200 Subject: [PATCH 026/210] Renaming --- .../Topology/Algebra/Module/Complement.lean | 136 +++++++++--------- 1 file changed, 70 insertions(+), 66 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index a5234b4eec19f2..06bc3d9bd79eb3 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -148,153 +148,157 @@ theorem _root_.ContinuousLinearMap.isTopCompl_of_proj {f : M →L[R] p} (hf : section projectionOnto +variable (p q) in /-- If `h : IsTopCompl p q`, `h.projectionOnto` is the continuous linear projection `M →L[R] p` along `q`. This is the continuous version of `Submodule.linearProjOfIsCompl`. See also `Submodule.IsTopCompl.projection` for the same projection as an element of `M →L[R] M`. -/ -protected noncomputable def IsTopCompl.projectionOnto (h : IsTopCompl p q) : M →L[R] p := +noncomputable def projectionOntoL (h : IsTopCompl p q) : M →L[R] p := ⟨p.linearProjOfIsCompl q h.isCompl, h.continuous_linearProjOfIsCompl⟩ @[simp] -theorem IsTopCompl.toLinearMap_projectionOnto (h : IsTopCompl p q) : - (h.projectionOnto : M →ₗ[R] p) = p.linearProjOfIsCompl q h.isCompl := +theorem toLinearMap_projectionOntoL (h : IsTopCompl p q) : + p.projectionOntoL q h = p.linearProjOfIsCompl q h.isCompl := rfl @[simp] -theorem IsTopCompl.projectionOnto_apply_left (h : IsTopCompl p q) (x : p) : - h.projectionOnto x = x := +theorem projectionOntoL_apply_left (h : IsTopCompl p q) (x : p) : + p.projectionOntoL q h x = x := linearProjOfIsCompl_apply_left h.isCompl x -theorem IsTopCompl.range_projectionOnto (h : IsTopCompl p q) : h.projectionOnto.range = ⊤ := +theorem range_projectionOntoL (h : IsTopCompl p q) : (p.projectionOntoL q h).range = ⊤ := linearProjOfIsCompl_range h.isCompl -theorem IsTopCompl.projectionOnto_surjective (h : IsTopCompl p q) : Surjective h.projectionOnto := +theorem projectionOntoL_surjective (h : IsTopCompl p q) : Surjective (p.projectionOntoL q h) := linearProjOfIsCompl_surjective h.isCompl @[simp] -theorem IsTopCompl.projectionOnto_apply_eq_zero_iff (h : IsTopCompl p q) {x : M} : - h.projectionOnto x = 0 ↔ x ∈ q := +theorem projectionOntoL_apply_eq_zero_iff (h : IsTopCompl p q) {x : M} : + p.projectionOntoL q h x = 0 ↔ x ∈ q := linearProjOfIsCompl_apply_eq_zero_iff h.isCompl -alias ⟨_, IsTopCompl.projectionOnto_apply_eq_zero_of_mem_right⟩ := - IsTopCompl.projectionOnto_apply_eq_zero_iff +alias ⟨_, projectionOntoL_apply_eq_zero_of_mem_right⟩ := + projectionOntoL_apply_eq_zero_iff @[simp] -theorem IsTopCompl.projectionOnto_apply_right (h : IsTopCompl p q) (x : q) : - h.projectionOnto x = 0 := - h.projectionOnto_apply_eq_zero_of_mem_right x.2 +theorem projectionOntoL_apply_right (h : IsTopCompl p q) (x : q) : + p.projectionOntoL q h x = 0 := + projectionOntoL_apply_eq_zero_of_mem_right h x.2 -theorem IsTopCompl.ker_projectionOnto (h : IsTopCompl p q) : - h.projectionOnto.ker = q := +theorem ker_projectionOntoL (h : IsTopCompl p q) : + (p.projectionOntoL q h).ker = q := linearProjOfIsCompl_ker h.isCompl -theorem IsTopCompl.isQuotientMap_projectionOnto (h : IsTopCompl p q) : - IsQuotientMap h.projectionOnto := - .of_inverse continuous_subtype_val h.projectionOnto.continuous h.projectionOnto_apply_left +theorem isQuotientMap_projectionOntoL (h : IsTopCompl p q) : + IsQuotientMap (p.projectionOntoL q h) := + .of_inverse continuous_subtype_val (p.projectionOntoL q h).continuous + (projectionOntoL_apply_left h) end projectionOnto section projection +variable (p q) in /-- If `h : IsTopCompl p q`, `h.projection` is the continuous linear projection `M →L[R] M` onto `p` along `q`. This is the continuous version of `Submodule.IsCompl.projection`. See also `Submodule.IsTopCompl.projectionOnto` for the same projection as an element of `M →L[R] p`. -/ -protected noncomputable def IsTopCompl.projection (h : IsTopCompl p q) : M →L[R] M := - p.subtypeL ∘L h.projectionOnto +noncomputable def projectionL (h : IsTopCompl p q) : M →L[R] M := + p.subtypeL ∘L p.projectionOntoL q h @[simp] -theorem IsTopCompl.toLinearMap_projection (h : IsTopCompl p q) : - (h.projection : M →ₗ[R] M) = h.isCompl.projection := +theorem toLinearMap_projectionL (h : IsTopCompl p q) : + p.projectionL q h = h.isCompl.projection := rfl -theorem IsTopCompl.projection_apply (h : IsTopCompl p q) (x : M) : - h.projection x = h.projectionOnto x := +theorem projectionL_apply (h : IsTopCompl p q) (x : M) : + p.projectionL q h x = p.projectionOntoL q h x := rfl @[simp] -theorem IsTopCompl.coe_projectionOnto_apply (h : IsTopCompl p q) (x : M) : - (h.projectionOnto x : M) = h.projection x := +theorem coe_projectionOntoL_apply (h : IsTopCompl p q) (x : M) : + (p.projectionOntoL q h x : M) = p.projectionL q h x := rfl @[simp] -theorem IsTopCompl.projection_apply_mem (h : IsTopCompl p q) (x : M) : - h.projection x ∈ p := +theorem projectionL_apply_mem (h : IsTopCompl p q) (x : M) : + p.projectionL q h x ∈ p := SetLike.coe_mem _ @[simp] -theorem IsTopCompl.projection_apply_left (h : IsTopCompl p q) (x : p) : - h.projection x = x := +theorem projectionL_apply_left (h : IsTopCompl p q) (x : p) : + p.projectionL q h x = x := h.isCompl.projection_apply_left x -theorem IsTopCompl.range_projection (h : IsTopCompl p q) : - h.projection.range = p := +theorem range_projectionL (h : IsTopCompl p q) : + (p.projectionL q h).range = p := h.isCompl.projection_range @[simp] -theorem IsTopCompl.projection_apply_eq_zero_iff (h : IsTopCompl p q) {x : M} : - h.projection x = 0 ↔ x ∈ q := +theorem projectionL_apply_eq_zero_iff (h : IsTopCompl p q) {x : M} : + p.projectionL q h x = 0 ↔ x ∈ q := h.isCompl.projection_apply_eq_zero_iff -alias ⟨_, IsTopCompl.projection_apply_eq_zero_of_mem_right⟩ := - IsTopCompl.projection_apply_eq_zero_iff +alias ⟨_, projectionL_apply_eq_zero_of_mem_right⟩ := + projectionL_apply_eq_zero_iff @[simp] -theorem IsTopCompl.projection_apply_right (h : IsTopCompl p q) (x : q) : - h.projection x = 0 := - h.projection_apply_eq_zero_of_mem_right x.2 +theorem projectionL_apply_right (h : IsTopCompl p q) (x : q) : + p.projectionL q h x = 0 := + projectionL_apply_eq_zero_of_mem_right h x.2 -theorem IsTopCompl.ker_projection (h : IsTopCompl p q) : - h.projection.ker = q := +theorem ker_projectionL (h : IsTopCompl p q) : + (p.projectionL q h).ker = q := h.isCompl.projection_ker @[simp] -theorem IsTopCompl.isIdempotentElem_projection (h : IsTopCompl p q) : - IsIdempotentElem h.projection := by +theorem isIdempotentElem_projectionL (h : IsTopCompl p q) : + IsIdempotentElem (p.projectionL q h) := by simp [← isIdempotentElem_toLinearMap_iff] -theorem IsTopCompl.projection_add_projection_eq_self [ContinuousSub M] +theorem projectionL_add_projectionL_eq_self [ContinuousSub M] (h : IsTopCompl p q) (x : M) : - h.projection x + h.symm.projection x = x := + p.projectionL q h x + q.projectionL p h.symm x = x := h.isCompl.projection_add_projection_eq_self x -theorem IsTopCompl.projection_add_projection_eq_id [IsTopologicalAddGroup M] (h : IsTopCompl p q) : - h.projection + h.symm.projection = .id R M := - ContinuousLinearMap.ext h.projection_add_projection_eq_self +theorem projectionL_add_projectionL_eq_id [IsTopologicalAddGroup M] (h : IsTopCompl p q) : + p.projectionL q h + q.projectionL p h.symm = .id R M := + ContinuousLinearMap.ext <| projectionL_add_projectionL_eq_self h -lemma IsTopCompl.projection_eq_self_sub_projection [ContinuousSub M] (h : IsTopCompl p q) (x : M) : - h.symm.projection x = x - h.projection x := by - rw [eq_sub_iff_add_eq, projection_add_projection_eq_self] +lemma projectionL_eq_self_sub_projectionL [ContinuousSub M] (h : IsTopCompl p q) (x : M) : + q.projectionL p h.symm x = x - p.projectionL q h x := by + rw [eq_sub_iff_add_eq, projectionL_add_projectionL_eq_self] -lemma IsTopCompl.projection_eq_id_sub_projection [IsTopologicalAddGroup M] (h : IsTopCompl p q) : - h.symm.projection = .id R M - h.projection := - ContinuousLinearMap.ext h.projection_eq_self_sub_projection +lemma projectionL_eq_id_sub_projectionL [IsTopologicalAddGroup M] (h : IsTopCompl p q) : + q.projectionL p h.symm = .id R M - p.projectionL q h := + ContinuousLinearMap.ext <| projectionL_eq_self_sub_projectionL h /-- The projection to `p` along `q` of `x` equals `x` if and only if `x ∈ p`. -/ -@[simp] lemma IsTopCompl.projection_eq_self_iff [ContinuousSub M] (h : IsTopCompl p q) (x : M) : - h.projection x = x ↔ x ∈ p := +@[simp] lemma projection_eq_self_iff [ContinuousSub M] (h : IsTopCompl p q) (x : M) : + p.projectionL q h x = x ↔ x ∈ p := h.isCompl.projection_eq_self_iff x -theorem _root_.ContinuousLinearMap.IsIdempotentElem.eq_isTopCompl_projection - {f : M →L[R] M} (hf : IsIdempotentElem f) : f = hf.isTopCompl.projection := +theorem _root_.ContinuousLinearMap.IsIdempotentElem.eq_projectionL + {f : M →L[R] M} (hf : IsIdempotentElem f) : f = f.range.projectionL f.ker hf.isTopCompl := coe_inj.mp <| LinearMap.IsIdempotentElem.eq_isCompl_projection hf.toLinearMap -theorem _root_.ContinuousLinearMap.isIdempotentElem_iff_eq_isTopCompl_projection_range_ker - {f : M →L[R] M} : IsIdempotentElem f ↔ ∃ h : IsTopCompl f.range f.ker, f = h.projection := - ⟨fun h ↦ ⟨_, h.eq_isTopCompl_projection⟩, fun ⟨hf, h⟩ ↦ h.symm ▸ hf.isIdempotentElem_projection⟩ +theorem _root_.ContinuousLinearMap.isIdempotentElem_iff_eq_projectionL_range_ker + {f : M →L[R] M} : IsIdempotentElem f ↔ + ∃ h : IsTopCompl f.range f.ker, f = f.range.projectionL f.ker h := + ⟨fun h ↦ ⟨_, h.eq_projectionL⟩, fun ⟨hf, h⟩ ↦ h.symm ▸ isIdempotentElem_projectionL hf⟩ end projection section closed_hausdorff theorem IsTopCompl.closedComplemented (h : IsTopCompl p q) : ClosedComplemented p := - ⟨h.projectionOnto, h.projectionOnto_apply_left⟩ + ⟨p.projectionOntoL q h, projectionOntoL_apply_left h⟩ /-- A variant of `Submodule.IsTopCompl.isClosed`. This has the very mild advantage over `h.symm.isClosed` that it doesn't assume `ContinuousSub M`. -/ theorem IsTopCompl.isClosed' [T1Space p] (h : IsTopCompl p q) : IsClosed (q : Set M) := by - rw [← ker_projectionOnto h] + rw [← ker_projectionOntoL h] exact isClosed_ker _ /-- If `p` and `q` are topological complements and `q` is Hausdorff, then `p` is closed. -/ @@ -305,8 +309,8 @@ protected theorem IsTopCompl.isClosed [T1Space q] [ContinuousSub M] (h : IsTopCo protected theorem IsTopCompl.t3Space [IsTopologicalAddGroup M] (h : IsTopCompl p q) (hq : IsClosed (q : Set M)) : T3Space p := by have : IsClosed ({0} : Set p) := by - rw [← h.isQuotientMap_projectionOnto.isClosed_preimage] - rwa [← h.ker_projectionOnto] at hq + rw [← (isQuotientMap_projectionOntoL h).isClosed_preimage] + rwa [← ker_projectionOntoL h] at hq have : T1Space p := IsTopologicalAddGroup.t1Space _ this rw [RegularSpace.t3Space_iff_t0Space] infer_instance From 67783e4e81bd8e6ed1c7ee13aca9f60d7553bc77 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Mon, 4 May 2026 13:41:17 +0200 Subject: [PATCH 027/210] nodot --- Mathlib/Topology/Algebra/Module/Complement.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 06bc3d9bd79eb3..80c18892e4b717 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -83,6 +83,7 @@ open ContinuousLinearMap /-- Two submodules `p` and `q` are *topological complements* if they are algebraic complements and the projection on `p` along `q` is continuous. -/ +@[pp_nodot] structure IsTopCompl (p q : Submodule R M) : Prop where isCompl : IsCompl p q continuous_projection : Continuous isCompl.projection From 7622d910537500123a99559cc881cfdb7ba525ba Mon Sep 17 00:00:00 2001 From: ADedecker Date: Mon, 4 May 2026 13:44:04 +0200 Subject: [PATCH 028/210] Undo one deprecation --- Mathlib/LinearAlgebra/Projection.lean | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Mathlib/LinearAlgebra/Projection.lean b/Mathlib/LinearAlgebra/Projection.lean index a2ee36737004b2..2de738aa8ad04e 100644 --- a/Mathlib/LinearAlgebra/Projection.lean +++ b/Mathlib/LinearAlgebra/Projection.lean @@ -237,13 +237,10 @@ theorem linearProjOfIsCompl_isCompl_projection (h : IsCompl p q) (x : E) : /-- The linear projection onto a subspace along its complement is an idempotent. -/ @[simp] -theorem IsCompl.isIdempotentElem_projection (hpq : IsCompl p q) : +theorem IsCompl.projection_isIdempotentElem (hpq : IsCompl p q) : IsIdempotentElem hpq.projection := LinearMap.ext fun _ ↦ congr($(linearProjOfIsCompl_isCompl_projection hpq _)) -@[deprecated (since := "2026-04-29")] -alias IsCompl.projection_isIdempotentElem := IsCompl.isIdempotentElem_projection - theorem existsUnique_add_of_isCompl_prod (hc : IsCompl p q) (x : E) : ∃! u : p × q, (u.fst : E) + u.snd = x := (prodEquivOfIsCompl _ _ hc).toEquiv.bijective.existsUnique _ From 471702120732d34299b8a9e3a3f230aa7e68127e Mon Sep 17 00:00:00 2001 From: ADedecker Date: Mon, 4 May 2026 13:44:44 +0200 Subject: [PATCH 029/210] fix --- Mathlib/LinearAlgebra/Projection.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/LinearAlgebra/Projection.lean b/Mathlib/LinearAlgebra/Projection.lean index 2de738aa8ad04e..a9c421c1a3175a 100644 --- a/Mathlib/LinearAlgebra/Projection.lean +++ b/Mathlib/LinearAlgebra/Projection.lean @@ -627,7 +627,7 @@ onto its range along its kernel. -/ theorem isIdempotentElem_iff_eq_isCompl_projection_range_ker {T : E →ₗ[R] E} : IsIdempotentElem T ↔ ∃ (h : IsCompl (range T) (ker T)), T = h.projection := ⟨fun hT => ⟨hT.isProj_range.isCompl, hT.eq_isCompl_projection⟩, - fun ⟨hT, h⟩ => h.symm ▸ hT.isIdempotentElem_projection⟩ + fun ⟨hT, h⟩ => h.symm ▸ hT.projection_isIdempotentElem⟩ open LinearMap in /-- Given an idempotent linear operator `q`, From 19662e52b58f97b67aa5941c9e0faef46f8b3675 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Mon, 4 May 2026 13:45:35 +0200 Subject: [PATCH 030/210] fix again --- Mathlib/Analysis/InnerProductSpace/Symmetric.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Analysis/InnerProductSpace/Symmetric.lean b/Mathlib/Analysis/InnerProductSpace/Symmetric.lean index c0f26a3005dde5..7e1e1f9124a3e8 100644 --- a/Mathlib/Analysis/InnerProductSpace/Symmetric.lean +++ b/Mathlib/Analysis/InnerProductSpace/Symmetric.lean @@ -305,7 +305,7 @@ open Submodule in theorem _root_.Submodule.IsCompl.projection_isSymmetricProjection_iff {U V : Submodule 𝕜 E} (hUV : IsCompl U V) : hUV.projection.IsSymmetricProjection ↔ U ⟂ V := by - simp [isSymmetricProjection_iff, hUV.projection_isSymmetric_iff, hUV.isIdempotentElem_projection] + simp [isSymmetricProjection_iff, hUV.projection_isSymmetric_iff, hUV.projection_isIdempotentElem] alias ⟨_, _root_.Submodule.IsCompl.projection_isSymmetricProjection_of_isOrtho⟩ := _root_.Submodule.IsCompl.projection_isSymmetricProjection_iff From f554eb6bff56ca9d3cb33f19c5af9de665828f00 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 5 May 2026 12:47:32 +0200 Subject: [PATCH 031/210] untested --- Mathlib/Topology/Algebra/Module/FiniteDimension.lean | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean index 9f7b6eefe9f7c8..d0528d5284ba5a 100644 --- a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean +++ b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean @@ -715,10 +715,9 @@ is a topological complement. -/ theorem IsCompl.isTopCompl_of_quotient_finiteDimensional {p q : Submodule 𝕜 E} (h : IsCompl p q) (hp : IsClosed (p : Set E)) [FiniteDimensional 𝕜 (E ⧸ p)] : IsTopCompl p q := by - let mkQ : E →L[𝕜] E ⧸ p := ⟨p.mkQ, continuous_quot_mk⟩ -- I can't believe we don't have this... let φ : E ⧸ p →L[𝕜] q := (p.quotientEquivOfIsCompl q h).toLinearMap.toContinuousLinearMap - have := (φ ∘L mkQ).isTopCompl_of_proj fun x ↦ by simp [mkQ, φ] - simpa [φ, mkQ] using this.symm + have := (φ ∘L p.mkQL).isTopCompl_of_proj fun x ↦ by simp [φ] + simpa [φ] using this.symm /-- Assume that `p q : Submodule 𝕜 E` are algebraic complements. If `p` is closed and `q` has finite dimension, then they are in fact topological complements. From 0ec756d99bf6d91067c247ca01138a3cc7bda923 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 5 May 2026 14:47:15 +0200 Subject: [PATCH 032/210] extra namespaces --- Mathlib/Topology/Algebra/Module/FiniteDimension.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean index d0528d5284ba5a..556430128ff317 100644 --- a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean +++ b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean @@ -712,7 +712,7 @@ open Submodule /-- If `p` is a closed subspace with finite codimension, then any algebraic complement `q` to `p` is a topological complement. -/ -theorem IsCompl.isTopCompl_of_quotient_finiteDimensional {p q : Submodule 𝕜 E} +theorem Submodule.IsCompl.isTopCompl_of_quotient_finiteDimensional {p q : Submodule 𝕜 E} (h : IsCompl p q) (hp : IsClosed (p : Set E)) [FiniteDimensional 𝕜 (E ⧸ p)] : IsTopCompl p q := by let φ : E ⧸ p →L[𝕜] q := (p.quotientEquivOfIsCompl q h).toLinearMap.toContinuousLinearMap @@ -725,7 +725,7 @@ has finite dimension, then they are in fact topological complements. Note that this theorem is not useful at all if you start from the finite dimensional subspace `q`, because building a closed complement requires the Hahn-Banach theorem (and you don't get control over what the complement is). See `Submodule.ClosedComplemented.of_finiteDimensional`. -/ -theorem IsCompl.isTopCompl_of_isClosed_of_finiteDimensional {p q : Submodule 𝕜 E} +theorem Submodule.IsCompl.isTopCompl_of_isClosed_of_finiteDimensional {p q : Submodule 𝕜 E} (h : IsCompl p q) (hp : IsClosed (p : Set E)) [hq : FiniteDimensional 𝕜 q] : IsTopCompl p q := by suffices FiniteDimensional 𝕜 (E ⧸ p) from h.isTopCompl_of_quotient_finiteDimensional hp From 0a2b6f63d112dc848c224c787d228499d03d5265 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 5 May 2026 18:26:32 +0200 Subject: [PATCH 033/210] Better docstring --- Mathlib/Topology/Algebra/Module/FiniteDimension.lean | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean index 556430128ff317..d65677d69e499b 100644 --- a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean +++ b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean @@ -722,9 +722,9 @@ theorem Submodule.IsCompl.isTopCompl_of_quotient_finiteDimensional {p q : Submod /-- Assume that `p q : Submodule 𝕜 E` are algebraic complements. If `p` is closed and `q` has finite dimension, then they are in fact topological complements. -Note that this theorem is not useful at all if you start from the finite dimensional subspace `q`, -because building a closed complement requires the Hahn-Banach theorem (and you don't get control -over what the complement is). See `Submodule.ClosedComplemented.of_finiteDimensional`. -/ +Note that this theorem does not help you to build a closed complement to a finite dimensional +subspace. This requires the Hahn-Banach theorem, and you don't get much control over what the +complement is. See `Submodule.ClosedComplemented.of_finiteDimensional`. -/ theorem Submodule.IsCompl.isTopCompl_of_isClosed_of_finiteDimensional {p q : Submodule 𝕜 E} (h : IsCompl p q) (hp : IsClosed (p : Set E)) [hq : FiniteDimensional 𝕜 q] : IsTopCompl p q := by From efcffb5c062d7cf8951090c3239a5b632528b176 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 8 May 2026 19:25:44 +0200 Subject: [PATCH 034/210] Step 1 done (essentially) ! --- .../Operator/Perturbation/StrictByFinite.lean | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean new file mode 100644 index 00000000000000..8b9742d9cbced8 --- /dev/null +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -0,0 +1,63 @@ +/- +Copyright (c) 2026 Anatole Dedecker. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Anatole Dedecker +-/ +module + +public import Mathlib.Topology.Maps.Strict.Basic +public import Mathlib.Topology.Algebra.Module.FiniteDimension + +/-! +# Strict linear maps with closed range are closed under finite-rank perturbation +-/ + +@[expose] public section + +open Topology Set Submodule Function + +variable {𝕜₁ 𝕜₂} + [NontriviallyNormedField 𝕜₁] [CompleteSpace 𝕜₁] + [NontriviallyNormedField 𝕜₂] [CompleteSpace 𝕜₂] + {σ : 𝕜₁ →+* 𝕜₂} + +variable {E F : Type*} + [AddCommGroup E] [Module 𝕜₁ E] [AddCommGroup F] [Module 𝕜₂ F] + [TopologicalSpace E] [IsTopologicalAddGroup E] [ContinuousSMul 𝕜₁ E] + [TopologicalSpace F] [IsTopologicalAddGroup F] [ContinuousSMul 𝕜₂ F] + +section FiniteCodimSubspace + +variable (A : Submodule 𝕜₁ E) (u : E →SL[σ] F) + +theorem step1 [RingHomSurjective σ] (A_closed : IsClosed (A : Set E)) + [codim_A : FiniteDimensional 𝕜₁ (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_strict : IsStrictMap u) + (h_closed : IsClosed (u.range : Set F)) : IsClosedEmbedding (restrict A u) := by + -- TODO: `Submodule.liftQL` ? + let u' : E ⧸ u.ker →ₛₗ[σ] F := u.ker.liftQ u le_rfl + have u'_clemb : IsClosedEmbedding u' := by + constructor + · rw [isStrictMap_iff_isEmbedding_kerLift] at h_strict + -- exact h_strict + sorry -- should be fixed with more API on strict homs + · simpa [u', ← LinearMap.coe_range, Submodule.range_liftQ] + let π : E →L[𝕜₁] E ⧸ u.ker := u.ker.mkQL + have π_restr_clemb : IsClosedEmbedding (restrict A π) := by + constructor + · rcases h_ker.exists_isCompl with ⟨S, ker_le_S, S_compl_A⟩ + replace S_compl_A : IsTopCompl S A := + S_compl_A.symm.isTopCompl_of_quotient_finiteDimensional A_closed |>.symm + -- TODO: `Submodule.liftQL` + let s : E ⧸ u.ker →L[𝕜₁] A := + ⟨u.ker.liftQ (A.projectionOntoL S S_compl_A.symm) (by simpa), + continuous_quot_lift _ (A.projectionOntoL S S_compl_A.symm).continuous⟩ + have leftInv : LeftInverse s (restrict A π) := fun x ↦ by simp [π, s] + refine .of_leftInverse leftInv s.continuous (by fun_prop) + · rw [← u.ker.isQuotientMap_mkQL.isClosed_preimage, range_restrict] + change IsClosed (comap π.toLinearMap (map π.toLinearMap A) : Set E) + exact isClosed_mono_of_finiteDimensional_quotient A_closed (le_comap_map _ A) + have eq : restrict A u = u' ∘ restrict A π := by ext x; simp [π, u'] + rw [eq] + exact u'_clemb.comp π_restr_clemb + +end FiniteCodimSubspace From 64bde2721e95f426171e95ece58d14b61740c11e Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 8 May 2026 20:53:16 +0200 Subject: [PATCH 035/210] Progress --- .../Operator/Perturbation/StrictByFinite.lean | 66 ++++++++++++------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 8b9742d9cbced8..6b86f0eaa2e84e 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -16,23 +16,39 @@ public import Mathlib.Topology.Algebra.Module.FiniteDimension open Topology Set Submodule Function -variable {𝕜₁ 𝕜₂} +variable {𝕜 𝕜₁ 𝕜₂} + [NontriviallyNormedField 𝕜] [CompleteSpace 𝕜] [NontriviallyNormedField 𝕜₁] [CompleteSpace 𝕜₁] [NontriviallyNormedField 𝕜₂] [CompleteSpace 𝕜₂] - {σ : 𝕜₁ →+* 𝕜₂} + {σ : 𝕜₁ →+* 𝕜₂} [RingHomSurjective σ] variable {E F : Type*} - [AddCommGroup E] [Module 𝕜₁ E] [AddCommGroup F] [Module 𝕜₂ F] - [TopologicalSpace E] [IsTopologicalAddGroup E] [ContinuousSMul 𝕜₁ E] - [TopologicalSpace F] [IsTopologicalAddGroup F] [ContinuousSMul 𝕜₂ F] + [AddCommGroup E] [Module 𝕜 E] [Module 𝕜₁ E] [AddCommGroup F] [Module 𝕜 F] [Module 𝕜₂ F] + [TopologicalSpace E] [IsTopologicalAddGroup E] [ContinuousSMul 𝕜 E] [ContinuousSMul 𝕜₁ E] + [TopologicalSpace F] [IsTopologicalAddGroup F] [ContinuousSMul 𝕜 F] [ContinuousSMul 𝕜₂ F] section FiniteCodimSubspace -variable (A : Submodule 𝕜₁ E) (u : E →SL[σ] F) +theorem step1_foward (A : Submodule 𝕜₁ E) (K : Submodule 𝕜₁ E) (A_closed : IsClosed (A : Set E)) + [codim_A : FiniteDimensional 𝕜₁ (E ⧸ A)] (K_disj_A : Disjoint K A) : + IsClosedEmbedding (restrict A K.mkQ) := by + constructor + · rcases K_disj_A.exists_isCompl with ⟨S, K_le_S, S_compl_A⟩ + replace S_compl_A : IsTopCompl S A := + S_compl_A.symm.isTopCompl_of_quotient_finiteDimensional A_closed |>.symm + -- TODO: `Submodule.liftQL` + let s : E ⧸ K →L[𝕜₁] A := + ⟨K.liftQ (A.projectionOntoL S S_compl_A.symm) (by simpa), + continuous_quot_lift _ (A.projectionOntoL S S_compl_A.symm).continuous⟩ + have leftInv : LeftInverse s (restrict A K.mkQ) := fun x ↦ by simp [s] + refine .of_leftInverse leftInv s.continuous (by fun_prop) + · rw [← K.isQuotientMap_mkQ.isClosed_preimage, range_restrict, ← Submodule.map_coe, + ← Submodule.comap_coe K.mkQ] + exact isClosed_mono_of_finiteDimensional_quotient A_closed (le_comap_map _ A) -theorem step1 [RingHomSurjective σ] (A_closed : IsClosed (A : Set E)) +theorem step2_forward (u : E →SL[σ] F) (A : Submodule 𝕜₁ E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜₁ (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_strict : IsStrictMap u) - (h_closed : IsClosed (u.range : Set F)) : IsClosedEmbedding (restrict A u) := by + (h_closed : IsClosed (range u)) : IsClosedEmbedding (restrict A u) := by -- TODO: `Submodule.liftQL` ? let u' : E ⧸ u.ker →ₛₗ[σ] F := u.ker.liftQ u le_rfl have u'_clemb : IsClosedEmbedding u' := by @@ -42,22 +58,28 @@ theorem step1 [RingHomSurjective σ] (A_closed : IsClosed (A : Set E)) sorry -- should be fixed with more API on strict homs · simpa [u', ← LinearMap.coe_range, Submodule.range_liftQ] let π : E →L[𝕜₁] E ⧸ u.ker := u.ker.mkQL - have π_restr_clemb : IsClosedEmbedding (restrict A π) := by - constructor - · rcases h_ker.exists_isCompl with ⟨S, ker_le_S, S_compl_A⟩ - replace S_compl_A : IsTopCompl S A := - S_compl_A.symm.isTopCompl_of_quotient_finiteDimensional A_closed |>.symm - -- TODO: `Submodule.liftQL` - let s : E ⧸ u.ker →L[𝕜₁] A := - ⟨u.ker.liftQ (A.projectionOntoL S S_compl_A.symm) (by simpa), - continuous_quot_lift _ (A.projectionOntoL S S_compl_A.symm).continuous⟩ - have leftInv : LeftInverse s (restrict A π) := fun x ↦ by simp [π, s] - refine .of_leftInverse leftInv s.continuous (by fun_prop) - · rw [← u.ker.isQuotientMap_mkQL.isClosed_preimage, range_restrict] - change IsClosed (comap π.toLinearMap (map π.toLinearMap A) : Set E) - exact isClosed_mono_of_finiteDimensional_quotient A_closed (le_comap_map _ A) + have π_restr_clemb : IsClosedEmbedding (restrict A π) := + step1_foward A u.ker A_closed h_ker have eq : restrict A u = u' ∘ restrict A π := by ext x; simp [π, u'] rw [eq] exact u'_clemb.comp π_restr_clemb +theorem foo (u : E →SL[σ] F) (A : Submodule 𝕜₁ E) (A_closed : IsClosed (A : Set E)) + [codim_A : FiniteDimensional 𝕜₁ (E ⧸ A)] : + (IsStrictMap u ∧ IsClosed (range u)) ↔ + (IsStrictMap (restrict A u) ∧ IsClosed (u '' A)) := by + sorry + end FiniteCodimSubspace + +section FiniteRank + +theorem bar [T1Space F] (u v : E →L[𝕜] F) (h_finite_rank : FiniteDimensional 𝕜 (u - v).range) : + (IsStrictMap u ∧ IsClosed (range u)) ↔ (IsStrictMap v ∧ IsClosed (range v)) := by + let A := (u - v).ker + have hA : IsClosed (A : Set E) := (u - v).isClosed_ker + have : FiniteDimensional 𝕜 (E ⧸ A) := (u - v).toLinearMap.quotKerEquivRange.symm.finiteDimensional + have eqOn_A : EqOn u v A := fun _ ↦ by simp [A, sub_eq_zero] + simp_rw [foo u A hA, foo v A hA, ← range_restrict, restrict_eq_restrict_iff.mpr eqOn_A] + +end FiniteRank From 88e06e66b7d217b7015f5b879f74bb7f3aed4b4d Mon Sep 17 00:00:00 2001 From: ADedecker Date: Sat, 9 May 2026 13:07:54 +0200 Subject: [PATCH 036/210] Reorganize and progress --- .../Operator/Perturbation/StrictByFinite.lean | 71 +++++++++++++++++-- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 6b86f0eaa2e84e..e6993117dd024b 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -12,8 +12,6 @@ public import Mathlib.Topology.Algebra.Module.FiniteDimension # Strict linear maps with closed range are closed under finite-rank perturbation -/ -@[expose] public section - open Topology Set Submodule Function variable {𝕜 𝕜₁ 𝕜₂} @@ -29,6 +27,32 @@ variable {E F : Type*} section FiniteCodimSubspace +/-! +## Proof of `ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict` + +Let `u : E →L[𝕜] F` be a continuous linear map, and `A` a finite codimension closed +subspace of `E`. We want to show that `u` is strict with closed range if and only if +`Set.restrict A u` is strict with closed range. + +We do the proof in three steps. +-/ + +/-! +### Step 1 + +We prove the theorem under the assumptions that +- `u` is surjective +- `u.ker` is disjoint from `A` (i.e. `u` is injective on `A`) + +The statement becomes: `u` is a quotient map if and only if `Set.restrict A u` is +a closed embedding. +-/ + +/-- The forward direction of step 1 in the proof of +`ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict`, which you should use instead. + +Note that we only prove it for `u = K.mkQ`, because it is easier and precisely what we will need +in step 2. -/ theorem step1_foward (A : Submodule 𝕜₁ E) (K : Submodule 𝕜₁ E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜₁ (E ⧸ A)] (K_disj_A : Disjoint K A) : IsClosedEmbedding (restrict A K.mkQ) := by @@ -46,6 +70,27 @@ theorem step1_foward (A : Submodule 𝕜₁ E) (K : Submodule 𝕜₁ E) (A_clos ← Submodule.comap_coe K.mkQ] exact isClosed_mono_of_finiteDimensional_quotient A_closed (le_comap_map _ A) +/-- The backward direction of step 1 in the proof of +`ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict`, which you should use instead. + +Note the hypothesis `h_ker` is implied `h_clemb`, but since this is a private theorem +we just write the most convenient statement to prove and use. -/ +theorem step1_backward (A : Submodule 𝕜₁ E) (u : E →SL[σ] F) (A_closed : IsClosed (A : Set E)) + [codim_A : FiniteDimensional 𝕜₁ (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) + (h_clemb : IsClosedEmbedding (restrict A u)) : + IsQuotientMap u := by + sorry + +/-! +### Step 2 + +We prove the theorem under the assumption that `u.ker` is disjoint from `A` +(i.e. `u` is injective on `A`). + +The statement becomes: `u` is strict with closed range if and only if `Set.restrict A u` is +a closed embedding. +-/ + theorem step2_forward (u : E →SL[σ] F) (A : Submodule 𝕜₁ E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜₁ (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_strict : IsStrictMap u) (h_closed : IsClosed (range u)) : IsClosedEmbedding (restrict A u) := by @@ -64,7 +109,19 @@ theorem step2_forward (u : E →SL[σ] F) (A : Submodule 𝕜₁ E) (A_closed : rw [eq] exact u'_clemb.comp π_restr_clemb -theorem foo (u : E →SL[σ] F) (A : Submodule 𝕜₁ E) (A_closed : IsClosed (A : Set E)) +theorem step2 (u : E →SL[σ] F) (A : Submodule 𝕜₁ E) (A_closed : IsClosed (A : Set E)) + [codim_A : FiniteDimensional 𝕜₁ (E ⧸ A)] (h_ker : Disjoint u.ker A) : + (IsStrictMap u ∧ IsClosed (range u)) ↔ IsClosedEmbedding (restrict A u) := by + sorry + +/-! +### Step 3 + +We now deduce from the two previous step the full strength of the theorem. +-/ + +public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict (u : E →SL[σ] F) + (A : Submodule 𝕜₁ E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜₁ (E ⧸ A)] : (IsStrictMap u ∧ IsClosed (range u)) ↔ (IsStrictMap (restrict A u) ∧ IsClosed (u '' A)) := by @@ -74,12 +131,16 @@ end FiniteCodimSubspace section FiniteRank -theorem bar [T1Space F] (u v : E →L[𝕜] F) (h_finite_rank : FiniteDimensional 𝕜 (u - v).range) : +-- TODO: state in terms of "equality modulo finite rank" relation +public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_finiteDimensional [T1Space F] + (u v : E →L[𝕜] F) (h_finite_rank : FiniteDimensional 𝕜 (u - v).range) : (IsStrictMap u ∧ IsClosed (range u)) ↔ (IsStrictMap v ∧ IsClosed (range v)) := by let A := (u - v).ker have hA : IsClosed (A : Set E) := (u - v).isClosed_ker have : FiniteDimensional 𝕜 (E ⧸ A) := (u - v).toLinearMap.quotKerEquivRange.symm.finiteDimensional have eqOn_A : EqOn u v A := fun _ ↦ by simp [A, sub_eq_zero] - simp_rw [foo u A hA, foo v A hA, ← range_restrict, restrict_eq_restrict_iff.mpr eqOn_A] + simp_rw [u.isStrictMap_isClosed_range_iff_restrict A hA, + v.isStrictMap_isClosed_range_iff_restrict A hA, + ← range_restrict, restrict_eq_restrict_iff.mpr eqOn_A] end FiniteRank From a4b71908f9956e3338ec6bff86aa2bb153745d7e Mon Sep 17 00:00:00 2001 From: ADedecker Date: Sun, 10 May 2026 14:10:56 +0200 Subject: [PATCH 037/210] Start on final reducion --- .../Operator/Perturbation/StrictByFinite.lean | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index e6993117dd024b..fd83c5c3337e71 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -120,11 +120,25 @@ theorem step2 (u : E →SL[σ] F) (A : Submodule 𝕜₁ E) (A_closed : IsClosed We now deduce from the two previous step the full strength of the theorem. -/ +#check quotientQuotientEquivQuotient + public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict (u : E →SL[σ] F) (A : Submodule 𝕜₁ E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜₁ (E ⧸ A)] : (IsStrictMap u ∧ IsClosed (range u)) ↔ (IsStrictMap (restrict A u) ∧ IsClosed (u '' A)) := by + set N : Submodule 𝕜₁ E := A ⊓ u.ker + set v : E ⧸ N →SL[σ] F := ⟨N.liftQ u inf_le_right, continuous_quot_lift _ u.continuous⟩ + have v_eq_u : v.comp N.mkQL = u := rfl + set B : Submodule 𝕜₁ (E ⧸ N) := map N.mkQ A + have comap_B : comap N.mkQ B = A := by simp [B, N] + have B_closed : IsClosed (B : Set <| E ⧸ N) := by + rwa [← N.isQuotientMap_mkQ.isClosed_preimage, ← comap_coe, comap_B] + have codim_B : FiniteDimensional 𝕜₁ ((E ⧸ N) ⧸ B) := + quotientQuotientEquivQuotient N A inf_le_left |>.symm.finiteDimensional + have range_eq : range v = range u := range_quot_lift _ + have image_eq : v '' B = u '' A := by simp [B, ← v_eq_u, ← image_comp] + rw [← range_eq, ← image_eq] sorry end FiniteCodimSubspace From b347b23507b77ba8dc5d5be4a8c46e2bd9e66833 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Sun, 10 May 2026 15:39:07 +0200 Subject: [PATCH 038/210] progress on step1 backwards --- .../Operator/Perturbation/StrictByFinite.lean | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index fd83c5c3337e71..9877f859ca1a37 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -70,15 +70,35 @@ theorem step1_foward (A : Submodule 𝕜₁ E) (K : Submodule 𝕜₁ E) (A_clos ← Submodule.comap_coe K.mkQ] exact isClosed_mono_of_finiteDimensional_quotient A_closed (le_comap_map _ A) +#check Codisjoint + /-- The backward direction of step 1 in the proof of `ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict`, which you should use instead. Note the hypothesis `h_ker` is implied `h_clemb`, but since this is a private theorem we just write the most convenient statement to prove and use. -/ -theorem step1_backward (A : Submodule 𝕜₁ E) (u : E →SL[σ] F) (A_closed : IsClosed (A : Set E)) - [codim_A : FiniteDimensional 𝕜₁ (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) +theorem step1_backward (A : Submodule 𝕜 E) (u : E →L[𝕜] F) (A_closed : IsClosed (A : Set E)) + [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) (h_clemb : IsClosedEmbedding (restrict A u)) : IsQuotientMap u := by + rcases h_ker.exists_isCompl with ⟨S, ker_le_S, S_compl_A⟩ + replace S_compl_A : IsTopCompl S A := + S_compl_A.symm.isTopCompl_of_quotient_finiteDimensional A_closed |>.symm + have : FiniteDimensional 𝕜 S := + quotientEquivOfIsCompl A S S_compl_A.isCompl.symm |>.finiteDimensional + have uA_closed : IsClosed (map u.toLinearMap A : Set F) := by + simpa [← range_restrict] using h_clemb.isClosed_range + have : FiniteDimensional 𝕜 (map u.toLinearMap S) := + show_term inferInstance + have uS_compl_uA : IsCompl (map u.toLinearMap S) (map u.toLinearMap A) := by + constructor + · rw [disjoint_iff, inf_comm, map_inf_eq_map_inf_comap, comap_map_eq, sup_eq_left.mpr ker_le_S, + S_compl_A.isCompl.symm.inf_eq_bot, Submodule.map_bot] + · rw [codisjoint_iff, ← Submodule.map_sup, S_compl_A.isCompl.sup_eq_top, Submodule.map_top, + h_range] + replace uS_compl_uA : IsTopCompl (map u.toLinearMap S) (map u.toLinearMap A) := + uS_compl_uA.symm.isTopCompl_of_isClosed_of_finiteDimensional uA_closed |>.symm + sorry /-! @@ -106,8 +126,7 @@ theorem step2_forward (u : E →SL[σ] F) (A : Submodule 𝕜₁ E) (A_closed : have π_restr_clemb : IsClosedEmbedding (restrict A π) := step1_foward A u.ker A_closed h_ker have eq : restrict A u = u' ∘ restrict A π := by ext x; simp [π, u'] - rw [eq] - exact u'_clemb.comp π_restr_clemb + exact eq ▸ u'_clemb.comp π_restr_clemb theorem step2 (u : E →SL[σ] F) (A : Submodule 𝕜₁ E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜₁ (E ⧸ A)] (h_ker : Disjoint u.ker A) : From 88655ff85148907b75b4af21f916587188a97d58 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Sun, 10 May 2026 15:41:16 +0200 Subject: [PATCH 039/210] undo semilinearize --- .../Operator/Perturbation/StrictByFinite.lean | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 9877f859ca1a37..608383540e604c 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -14,16 +14,13 @@ public import Mathlib.Topology.Algebra.Module.FiniteDimension open Topology Set Submodule Function -variable {𝕜 𝕜₁ 𝕜₂} +variable {𝕜} [NontriviallyNormedField 𝕜] [CompleteSpace 𝕜] - [NontriviallyNormedField 𝕜₁] [CompleteSpace 𝕜₁] - [NontriviallyNormedField 𝕜₂] [CompleteSpace 𝕜₂] - {σ : 𝕜₁ →+* 𝕜₂} [RingHomSurjective σ] variable {E F : Type*} - [AddCommGroup E] [Module 𝕜 E] [Module 𝕜₁ E] [AddCommGroup F] [Module 𝕜 F] [Module 𝕜₂ F] - [TopologicalSpace E] [IsTopologicalAddGroup E] [ContinuousSMul 𝕜 E] [ContinuousSMul 𝕜₁ E] - [TopologicalSpace F] [IsTopologicalAddGroup F] [ContinuousSMul 𝕜 F] [ContinuousSMul 𝕜₂ F] + [AddCommGroup E] [Module 𝕜 E] [AddCommGroup F] [Module 𝕜 F] + [TopologicalSpace E] [IsTopologicalAddGroup E] [ContinuousSMul 𝕜 E] + [TopologicalSpace F] [IsTopologicalAddGroup F] [ContinuousSMul 𝕜 F] section FiniteCodimSubspace @@ -53,15 +50,15 @@ a closed embedding. Note that we only prove it for `u = K.mkQ`, because it is easier and precisely what we will need in step 2. -/ -theorem step1_foward (A : Submodule 𝕜₁ E) (K : Submodule 𝕜₁ E) (A_closed : IsClosed (A : Set E)) - [codim_A : FiniteDimensional 𝕜₁ (E ⧸ A)] (K_disj_A : Disjoint K A) : +theorem step1_foward (A : Submodule 𝕜 E) (K : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) + [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (K_disj_A : Disjoint K A) : IsClosedEmbedding (restrict A K.mkQ) := by constructor · rcases K_disj_A.exists_isCompl with ⟨S, K_le_S, S_compl_A⟩ replace S_compl_A : IsTopCompl S A := S_compl_A.symm.isTopCompl_of_quotient_finiteDimensional A_closed |>.symm -- TODO: `Submodule.liftQL` - let s : E ⧸ K →L[𝕜₁] A := + let s : E ⧸ K →L[𝕜] A := ⟨K.liftQ (A.projectionOntoL S S_compl_A.symm) (by simpa), continuous_quot_lift _ (A.projectionOntoL S S_compl_A.symm).continuous⟩ have leftInv : LeftInverse s (restrict A K.mkQ) := fun x ↦ by simp [s] @@ -111,25 +108,25 @@ The statement becomes: `u` is strict with closed range if and only if `Set.restr a closed embedding. -/ -theorem step2_forward (u : E →SL[σ] F) (A : Submodule 𝕜₁ E) (A_closed : IsClosed (A : Set E)) - [codim_A : FiniteDimensional 𝕜₁ (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_strict : IsStrictMap u) +theorem step2_forward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) + [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_strict : IsStrictMap u) (h_closed : IsClosed (range u)) : IsClosedEmbedding (restrict A u) := by -- TODO: `Submodule.liftQL` ? - let u' : E ⧸ u.ker →ₛₗ[σ] F := u.ker.liftQ u le_rfl + let u' : E ⧸ u.ker →ₗ[𝕜] F := u.ker.liftQ u le_rfl have u'_clemb : IsClosedEmbedding u' := by constructor · rw [isStrictMap_iff_isEmbedding_kerLift] at h_strict -- exact h_strict sorry -- should be fixed with more API on strict homs · simpa [u', ← LinearMap.coe_range, Submodule.range_liftQ] - let π : E →L[𝕜₁] E ⧸ u.ker := u.ker.mkQL + let π : E →L[𝕜] E ⧸ u.ker := u.ker.mkQL have π_restr_clemb : IsClosedEmbedding (restrict A π) := step1_foward A u.ker A_closed h_ker have eq : restrict A u = u' ∘ restrict A π := by ext x; simp [π, u'] exact eq ▸ u'_clemb.comp π_restr_clemb -theorem step2 (u : E →SL[σ] F) (A : Submodule 𝕜₁ E) (A_closed : IsClosed (A : Set E)) - [codim_A : FiniteDimensional 𝕜₁ (E ⧸ A)] (h_ker : Disjoint u.ker A) : +theorem step2 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) + [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) : (IsStrictMap u ∧ IsClosed (range u)) ↔ IsClosedEmbedding (restrict A u) := by sorry @@ -141,19 +138,19 @@ We now deduce from the two previous step the full strength of the theorem. #check quotientQuotientEquivQuotient -public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict (u : E →SL[σ] F) - (A : Submodule 𝕜₁ E) (A_closed : IsClosed (A : Set E)) - [codim_A : FiniteDimensional 𝕜₁ (E ⧸ A)] : +public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict (u : E →L[𝕜] F) + (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) + [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] : (IsStrictMap u ∧ IsClosed (range u)) ↔ (IsStrictMap (restrict A u) ∧ IsClosed (u '' A)) := by - set N : Submodule 𝕜₁ E := A ⊓ u.ker - set v : E ⧸ N →SL[σ] F := ⟨N.liftQ u inf_le_right, continuous_quot_lift _ u.continuous⟩ + set N : Submodule 𝕜 E := A ⊓ u.ker + set v : E ⧸ N →L[𝕜] F := ⟨N.liftQ u inf_le_right, continuous_quot_lift _ u.continuous⟩ have v_eq_u : v.comp N.mkQL = u := rfl - set B : Submodule 𝕜₁ (E ⧸ N) := map N.mkQ A + set B : Submodule 𝕜 (E ⧸ N) := map N.mkQ A have comap_B : comap N.mkQ B = A := by simp [B, N] have B_closed : IsClosed (B : Set <| E ⧸ N) := by rwa [← N.isQuotientMap_mkQ.isClosed_preimage, ← comap_coe, comap_B] - have codim_B : FiniteDimensional 𝕜₁ ((E ⧸ N) ⧸ B) := + have codim_B : FiniteDimensional 𝕜 ((E ⧸ N) ⧸ B) := quotientQuotientEquivQuotient N A inf_le_left |>.symm.finiteDimensional have range_eq : range v = range u := range_quot_lift _ have image_eq : v '' B = u '' A := by simp [B, ← v_eq_u, ← image_comp] From 2d6ebf3e9cf92c04dbb9297bfdcedd68bcdb37a6 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Sun, 10 May 2026 15:47:03 +0200 Subject: [PATCH 040/210] ++ --- .../Normed/Operator/Perturbation/StrictByFinite.lean | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 608383540e604c..468badfe2adca7 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -85,8 +85,6 @@ theorem step1_backward (A : Submodule 𝕜 E) (u : E →L[𝕜] F) (A_closed : I quotientEquivOfIsCompl A S S_compl_A.isCompl.symm |>.finiteDimensional have uA_closed : IsClosed (map u.toLinearMap A : Set F) := by simpa [← range_restrict] using h_clemb.isClosed_range - have : FiniteDimensional 𝕜 (map u.toLinearMap S) := - show_term inferInstance have uS_compl_uA : IsCompl (map u.toLinearMap S) (map u.toLinearMap A) := by constructor · rw [disjoint_iff, inf_comm, map_inf_eq_map_inf_comap, comap_map_eq, sup_eq_left.mpr ker_le_S, @@ -95,7 +93,6 @@ theorem step1_backward (A : Submodule 𝕜 E) (u : E →L[𝕜] F) (A_closed : I h_range] replace uS_compl_uA : IsTopCompl (map u.toLinearMap S) (map u.toLinearMap A) := uS_compl_uA.symm.isTopCompl_of_isClosed_of_finiteDimensional uA_closed |>.symm - sorry /-! @@ -136,7 +133,7 @@ theorem step2 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed ( We now deduce from the two previous step the full strength of the theorem. -/ -#check quotientQuotientEquivQuotient +#check IsOpenQuotientMap public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) From 9b6c9764a50f58cea595fb9a0b29913c01195c3d Mon Sep 17 00:00:00 2001 From: ADedecker Date: Sun, 10 May 2026 15:53:29 +0200 Subject: [PATCH 041/210] Start on other corollary --- .../Operator/Perturbation/StrictByFinite.lean | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 468badfe2adca7..52a98c334b8f7d 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -171,3 +171,17 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_finiteDimen ← range_restrict, restrict_eq_restrict_iff.mpr eqOn_A] end FiniteRank + +section FiniteDimQuotient + +-- TODO: better name +-- TODO: use ∘ or ∘L ? The simp NF is ∘ +public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_quotient + (u : E →L[𝕜] F) (A : Submodule 𝕜 F) [dim_A : FiniteDimensional 𝕜 A] + (A_compl : ClosedComplemented A) : + (IsStrictMap u ∧ IsClosed (range u)) ↔ + (IsStrictMap (A.mkQ ∘ u) ∧ IsClosed (range (A.mkQ ∘ u))) := by + obtain ⟨S, A_compl_S⟩ := A_compl.exists_isTopCompl + sorry + +end FiniteDimQuotient From 94e7690ae9a0e379904af7033178a1d40c4c6bd6 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Sun, 10 May 2026 19:23:07 +0200 Subject: [PATCH 042/210] More stuff about strict maps --- .../Connected/TotallyDisconnected.lean | 2 +- Mathlib/Topology/Maps/Basic.lean | 4 +++ Mathlib/Topology/Maps/Strict/Basic.lean | 36 ++++++++++++++++++- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/Mathlib/Topology/Connected/TotallyDisconnected.lean b/Mathlib/Topology/Connected/TotallyDisconnected.lean index 6d275afa3d1ae6..f6fba4876114c5 100644 --- a/Mathlib/Topology/Connected/TotallyDisconnected.lean +++ b/Mathlib/Topology/Connected/TotallyDisconnected.lean @@ -306,7 +306,7 @@ theorem Continuous.connectedComponentsMap_continuous {β : Type*} [TopologicalSp lemma Topology.IsCoinducing.connectedComponentsMap {β : Type*} [TopologicalSpace β] {f : α → β} (hf : IsCoinducing f) : IsCoinducing hf.continuous.connectedComponentsMap := by - rw [← ConnectedComponents.isQuotientMap_coe.of_comp_iff] + rw [← ConnectedComponents.isQuotientMap_coe.isCoinducing.of_comp_iff] exact ConnectedComponents.isQuotientMap_coe.isCoinducing.comp hf @[simp] diff --git a/Mathlib/Topology/Maps/Basic.lean b/Mathlib/Topology/Maps/Basic.lean index 9a4a5b10c48085..6bf73efb15dc8e 100644 --- a/Mathlib/Topology/Maps/Basic.lean +++ b/Mathlib/Topology/Maps/Basic.lean @@ -328,6 +328,10 @@ theorem of_comp_of_isCoinducing (hgf : IsQuotientMap (g ∘ f)) (hf : IsCoinduci @[deprecated (since := "2026-03-21")] alias of_comp_of_eq_coinduced := of_comp_of_isCoinducing +protected theorem of_comp_iff (hf : IsQuotientMap f) : + IsQuotientMap (g ∘ f) ↔ IsQuotientMap g := by + rw [isQuotientMap_iff, isQuotientMap_iff, hf.isCoinducing.of_comp_iff, hf.surjective.of_comp_iff] + theorem of_comp_isQuotientMap (hf : IsQuotientMap f) (hgf : IsQuotientMap (g ∘ f)) : IsQuotientMap g := of_comp_of_isCoinducing hgf hf.isCoinducing diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index 061b5366a74842..5227db129abbc0 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -41,7 +41,8 @@ open Function Set Topology namespace Topology -variable {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] (f : X → Y) +variable {X Y Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] + (f : X → Y) {g : Y → Z} /-- A map is a strict map in the sense of Bourbaki if the natural map to its image is a quotient map. -/ @@ -96,5 +97,38 @@ lemma IsClosedMap.isStrictMap (hc : IsClosedMap f) (h_cont : Continuous f) : exact (hc.subtype_mk fun x => ⟨x, rfl⟩).isQuotientMap h_cont.rangeFactorization Set.rangeFactorization_surjective +lemma IsHomeomorph.isStrictMap (f_homeo : IsHomeomorph f) : + IsStrictMap f := + f_homeo.isOpenMap.isStrictMap f_homeo.continuous + +lemma IsStrictMap.id : IsStrictMap (id : X → X) := IsHomeomorph.id.isStrictMap + +lemma IsQuotientMap.isStrictMap_iff (f_quot : IsQuotientMap f) : + IsStrictMap g ↔ IsStrictMap (g ∘ f) := by + set Φ : range (g ∘ f) ≃ₜ range g := .setCongr <| f_quot.surjective.range_comp g + have key : rangeFactorization g ∘ f = Φ ∘ rangeFactorization (g ∘ f) := rfl + simp_rw [isStrictMap_iff_isQuotientMap_rangeFactorization, ← f_quot.of_comp_iff, key] + exact ⟨fun H ↦ by simpa using Φ.symm.isQuotientMap.comp H, fun H ↦ Φ.isQuotientMap.comp H⟩ + +lemma IsQuotientMap.isStrictMap (f_quot : IsQuotientMap f) : + IsStrictMap f := + f_quot.isStrictMap_iff.mp .id + +lemma IsEmbedding.isStrictMap_iff (g_emb : IsEmbedding g) : + IsStrictMap f ↔ IsStrictMap (g ∘ f) := by + have eq : Setoid.ker (g ∘ f) = Setoid.ker f := by ext; simp [g_emb.injective.eq_iff] + rw [isStrictMap_iff_isEmbedding_kerLift, isStrictMap_iff_isEmbedding_kerLift] + sorry + +lemma IsEmbedding.isStrictMap (f_emb : IsEmbedding f) : + IsStrictMap f := + f_emb.isStrictMap_iff.mp .id + +lemma isQuotientMap_iff_isStrictMap_surjective : + IsQuotientMap f ↔ IsStrictMap f ∧ Surjective f := by + refine ⟨fun H ↦ ⟨H.isStrictMap, H.surjective⟩, fun ⟨f_strict, f_surj⟩ ↦ ?_⟩ + rw [isStrictMap_iff_isQuotientMap_rangeFactorization] at f_strict + set Φ : range f ≃ₜ Y := .trans (.setCongr f_surj.range_eq) (Homeomorph.Set.univ Y) + exact Φ.isQuotientMap.comp f_strict end Topology From e0a16ba83734dee5c22a6213d14f4be900b52f28 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Sun, 10 May 2026 19:33:40 +0200 Subject: [PATCH 043/210] .. --- .../Normed/Operator/Perturbation/StrictByFinite.lean | 8 ++------ Mathlib/Topology/Maps/Strict/Basic.lean | 5 +++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 52a98c334b8f7d..75898f38595568 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -67,8 +67,6 @@ theorem step1_foward (A : Submodule 𝕜 E) (K : Submodule 𝕜 E) (A_closed : I ← Submodule.comap_coe K.mkQ] exact isClosed_mono_of_finiteDimensional_quotient A_closed (le_comap_map _ A) -#check Codisjoint - /-- The backward direction of step 1 in the proof of `ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict`, which you should use instead. @@ -112,9 +110,7 @@ theorem step2_forward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : Is let u' : E ⧸ u.ker →ₗ[𝕜] F := u.ker.liftQ u le_rfl have u'_clemb : IsClosedEmbedding u' := by constructor - · rw [isStrictMap_iff_isEmbedding_kerLift] at h_strict - -- exact h_strict - sorry -- should be fixed with more API on strict homs + · sorry -- should be fixed with more API on strict homs · simpa [u', ← LinearMap.coe_range, Submodule.range_liftQ] let π : E →L[𝕜] E ⧸ u.ker := u.ker.mkQL have π_restr_clemb : IsClosedEmbedding (restrict A π) := @@ -142,7 +138,7 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict (u : (IsStrictMap (restrict A u) ∧ IsClosed (u '' A)) := by set N : Submodule 𝕜 E := A ⊓ u.ker set v : E ⧸ N →L[𝕜] F := ⟨N.liftQ u inf_le_right, continuous_quot_lift _ u.continuous⟩ - have v_eq_u : v.comp N.mkQL = u := rfl + have v_eq_u : v ∘L N.mkQL = u := rfl set B : Submodule 𝕜 (E ⧸ N) := map N.mkQ A have comap_B : comap N.mkQ B = A := by simp [B, N] have B_closed : IsClosed (B : Set <| E ⧸ N) := by diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index 5227db129abbc0..955c3d37f8a1bb 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -131,4 +131,9 @@ lemma isQuotientMap_iff_isStrictMap_surjective : set Φ : range f ≃ₜ Y := .trans (.setCongr f_surj.range_eq) (Homeomorph.Set.univ Y) exact Φ.isQuotientMap.comp f_strict +lemma isEmbedding_iff_isStrictMap_injective : + IsEmbedding f ↔ IsStrictMap f ∧ Injective f := by + refine ⟨fun H ↦ ⟨H.isStrictMap, H.injective⟩, fun ⟨f_strict, f_inj⟩ ↦ ?_⟩ + sorry + end Topology From 06994b8440a3f7472311070c5e78785212d64ed4 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Sun, 10 May 2026 19:49:23 +0200 Subject: [PATCH 044/210] progress on step2 backwards --- .../Operator/Perturbation/StrictByFinite.lean | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 75898f38595568..2346578c13e152 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -118,6 +118,20 @@ theorem step2_forward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : Is have eq : restrict A u = u' ∘ restrict A π := by ext x; simp [π, u'] exact eq ▸ u'_clemb.comp π_restr_clemb +theorem step2_backward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) + [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) + (h_clemb : IsClosedEmbedding (restrict A u)) : + IsStrictMap u ∧ IsClosed (range u) := by + rcases A.exists_isCompl with ⟨S, A_compl_S⟩ + have : FiniteDimensional 𝕜 S := + quotientEquivOfIsCompl A S A_compl_S |>.finiteDimensional + rw [isClosedEmbedding_iff, range_restrict] at h_clemb + have : range u = (map u.toLinearMap A ⊔ map u.toLinearMap S) := by + rw [← Submodule.map_sup, A_compl_S.sup_eq_top, Submodule.map_top, + LinearMap.coe_range, ContinuousLinearMap.coe_coe] + refine ⟨?_, this ▸ Submodule.isClosed_sup_finiteDimensional _ _ h_clemb.2⟩ + sorry + theorem step2 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) : (IsStrictMap u ∧ IsClosed (range u)) ↔ IsClosedEmbedding (restrict A u) := by From f2669a070efab2713c81575bf48505265d609dca Mon Sep 17 00:00:00 2001 From: ADedecker Date: Mon, 11 May 2026 12:12:09 -0400 Subject: [PATCH 045/210] Fix names --- .../Analysis/Normed/Operator/Perturbation/StrictByFinite.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 2346578c13e152..00b1d63c621a67 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -56,7 +56,7 @@ theorem step1_foward (A : Submodule 𝕜 E) (K : Submodule 𝕜 E) (A_closed : I constructor · rcases K_disj_A.exists_isCompl with ⟨S, K_le_S, S_compl_A⟩ replace S_compl_A : IsTopCompl S A := - S_compl_A.symm.isTopCompl_of_quotient_finiteDimensional A_closed |>.symm + S_compl_A.symm.isTopCompl_of_finiteDimensional_quotient A_closed |>.symm -- TODO: `Submodule.liftQL` let s : E ⧸ K →L[𝕜] A := ⟨K.liftQ (A.projectionOntoL S S_compl_A.symm) (by simpa), @@ -78,7 +78,7 @@ theorem step1_backward (A : Submodule 𝕜 E) (u : E →L[𝕜] F) (A_closed : I IsQuotientMap u := by rcases h_ker.exists_isCompl with ⟨S, ker_le_S, S_compl_A⟩ replace S_compl_A : IsTopCompl S A := - S_compl_A.symm.isTopCompl_of_quotient_finiteDimensional A_closed |>.symm + S_compl_A.symm.isTopCompl_of_finiteDimensional_quotient A_closed |>.symm have : FiniteDimensional 𝕜 S := quotientEquivOfIsCompl A S S_compl_A.isCompl.symm |>.finiteDimensional have uA_closed : IsClosed (map u.toLinearMap A : Set F) := by From 6d29f853b233dc5753d29407ae9e826696d0b28e Mon Sep 17 00:00:00 2001 From: ADedecker Date: Mon, 11 May 2026 12:30:49 -0400 Subject: [PATCH 046/210] feat(Topology): test strictness on quotient and spaces --- .../Connected/TotallyDisconnected.lean | 2 +- Mathlib/Topology/Maps/Basic.lean | 4 ++ Mathlib/Topology/Maps/Strict/Basic.lean | 41 ++++++++++++++++++- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/Mathlib/Topology/Connected/TotallyDisconnected.lean b/Mathlib/Topology/Connected/TotallyDisconnected.lean index 6d275afa3d1ae6..f6fba4876114c5 100644 --- a/Mathlib/Topology/Connected/TotallyDisconnected.lean +++ b/Mathlib/Topology/Connected/TotallyDisconnected.lean @@ -306,7 +306,7 @@ theorem Continuous.connectedComponentsMap_continuous {β : Type*} [TopologicalSp lemma Topology.IsCoinducing.connectedComponentsMap {β : Type*} [TopologicalSpace β] {f : α → β} (hf : IsCoinducing f) : IsCoinducing hf.continuous.connectedComponentsMap := by - rw [← ConnectedComponents.isQuotientMap_coe.of_comp_iff] + rw [← ConnectedComponents.isQuotientMap_coe.isCoinducing.of_comp_iff] exact ConnectedComponents.isQuotientMap_coe.isCoinducing.comp hf @[simp] diff --git a/Mathlib/Topology/Maps/Basic.lean b/Mathlib/Topology/Maps/Basic.lean index 9a4a5b10c48085..6bf73efb15dc8e 100644 --- a/Mathlib/Topology/Maps/Basic.lean +++ b/Mathlib/Topology/Maps/Basic.lean @@ -328,6 +328,10 @@ theorem of_comp_of_isCoinducing (hgf : IsQuotientMap (g ∘ f)) (hf : IsCoinduci @[deprecated (since := "2026-03-21")] alias of_comp_of_eq_coinduced := of_comp_of_isCoinducing +protected theorem of_comp_iff (hf : IsQuotientMap f) : + IsQuotientMap (g ∘ f) ↔ IsQuotientMap g := by + rw [isQuotientMap_iff, isQuotientMap_iff, hf.isCoinducing.of_comp_iff, hf.surjective.of_comp_iff] + theorem of_comp_isQuotientMap (hf : IsQuotientMap f) (hgf : IsQuotientMap (g ∘ f)) : IsQuotientMap g := of_comp_of_isCoinducing hgf hf.isCoinducing diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index 061b5366a74842..955c3d37f8a1bb 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -41,7 +41,8 @@ open Function Set Topology namespace Topology -variable {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] (f : X → Y) +variable {X Y Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] + (f : X → Y) {g : Y → Z} /-- A map is a strict map in the sense of Bourbaki if the natural map to its image is a quotient map. -/ @@ -96,5 +97,43 @@ lemma IsClosedMap.isStrictMap (hc : IsClosedMap f) (h_cont : Continuous f) : exact (hc.subtype_mk fun x => ⟨x, rfl⟩).isQuotientMap h_cont.rangeFactorization Set.rangeFactorization_surjective +lemma IsHomeomorph.isStrictMap (f_homeo : IsHomeomorph f) : + IsStrictMap f := + f_homeo.isOpenMap.isStrictMap f_homeo.continuous + +lemma IsStrictMap.id : IsStrictMap (id : X → X) := IsHomeomorph.id.isStrictMap + +lemma IsQuotientMap.isStrictMap_iff (f_quot : IsQuotientMap f) : + IsStrictMap g ↔ IsStrictMap (g ∘ f) := by + set Φ : range (g ∘ f) ≃ₜ range g := .setCongr <| f_quot.surjective.range_comp g + have key : rangeFactorization g ∘ f = Φ ∘ rangeFactorization (g ∘ f) := rfl + simp_rw [isStrictMap_iff_isQuotientMap_rangeFactorization, ← f_quot.of_comp_iff, key] + exact ⟨fun H ↦ by simpa using Φ.symm.isQuotientMap.comp H, fun H ↦ Φ.isQuotientMap.comp H⟩ + +lemma IsQuotientMap.isStrictMap (f_quot : IsQuotientMap f) : + IsStrictMap f := + f_quot.isStrictMap_iff.mp .id + +lemma IsEmbedding.isStrictMap_iff (g_emb : IsEmbedding g) : + IsStrictMap f ↔ IsStrictMap (g ∘ f) := by + have eq : Setoid.ker (g ∘ f) = Setoid.ker f := by ext; simp [g_emb.injective.eq_iff] + rw [isStrictMap_iff_isEmbedding_kerLift, isStrictMap_iff_isEmbedding_kerLift] + sorry + +lemma IsEmbedding.isStrictMap (f_emb : IsEmbedding f) : + IsStrictMap f := + f_emb.isStrictMap_iff.mp .id + +lemma isQuotientMap_iff_isStrictMap_surjective : + IsQuotientMap f ↔ IsStrictMap f ∧ Surjective f := by + refine ⟨fun H ↦ ⟨H.isStrictMap, H.surjective⟩, fun ⟨f_strict, f_surj⟩ ↦ ?_⟩ + rw [isStrictMap_iff_isQuotientMap_rangeFactorization] at f_strict + set Φ : range f ≃ₜ Y := .trans (.setCongr f_surj.range_eq) (Homeomorph.Set.univ Y) + exact Φ.isQuotientMap.comp f_strict + +lemma isEmbedding_iff_isStrictMap_injective : + IsEmbedding f ↔ IsStrictMap f ∧ Injective f := by + refine ⟨fun H ↦ ⟨H.isStrictMap, H.injective⟩, fun ⟨f_strict, f_inj⟩ ↦ ?_⟩ + sorry end Topology From df7df2a5f78d6bebd0dca8c08c6665352f54b3fa Mon Sep 17 00:00:00 2001 From: ADedecker Date: Mon, 11 May 2026 18:57:12 -0400 Subject: [PATCH 047/210] ++ --- Mathlib/Logic/Equiv/Quotient.lean | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Mathlib/Logic/Equiv/Quotient.lean diff --git a/Mathlib/Logic/Equiv/Quotient.lean b/Mathlib/Logic/Equiv/Quotient.lean new file mode 100644 index 00000000000000..8b7c368b79e211 --- /dev/null +++ b/Mathlib/Logic/Equiv/Quotient.lean @@ -0,0 +1,37 @@ +/- +Copyright (c) 2026 Anatole Dedecker. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Anatole Dedecker +-/ +module + +public import Mathlib.Data.Set.Function +public import Mathlib.Logic.Equiv.Defs + +/-! +# Equivalences and quotients + +In this file we provide facts relating `Equiv` and `Quotient`. +-/ + +@[expose] public section + +open Function Set + +variable {α β γ : Type*} + +namespace Equiv + +@[simps] +protected def quotCongr {r s : α → α → Prop} (eq : r = s) : Quot r ≃ Quot s where + toFun := Quot.lift (Quot.mk s) (by simp [eq, Quot.congr_mk]) + invFun := sorry + left_inv := sorry + right_inv := sorry + +/-- If `α` is equivalent to `β`, then `Set α` is equivalent to `Set β`. -/ +@[simps] +protected def congr {α β : Type*} (e : α ≃ β) : Set α ≃ Set β := + ⟨fun s => e '' s, fun t => e.symm '' t, symm_image_image e, symm_image_image e.symm⟩ + +end Equiv From 4e7a8e477ddd92f93003f8f6aba14da630a2c6a7 Mon Sep 17 00:00:00 2001 From: sharky564 Date: Sat, 2 May 2026 17:51:49 +1000 Subject: [PATCH 048/210] Added CLM.ofIsTopCompl --- .../Topology/Algebra/Module/Complement.lean | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 5945ceef62f939..6e9dd0dd70342a 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -400,3 +400,55 @@ lemma ClosedComplemented.exists_submodule_equiv_prod [IsTopologicalAddGroup M] end ClosedComplemented end Submodule + +namespace ContinuousLinearMap + +variable {R : Type*} [Ring R] {E F : Type*} + [TopologicalSpace E] [AddCommGroup E] [Module R E] [IsTopologicalAddGroup E] + [TopologicalSpace F] [AddCommGroup F] [Module R F] [ContinuousAdd F] + {p q : Submodule R E} + +/-- Given continuous linear maps `φ : p →L[R] F` and `ψ : q →L[R] F` from topological complement +submodules of `E`, the induced continuous linear map `E →L[R] F`. -/ +noncomputable def ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : E →L[R] F := + φ ∘L h.projectionOnto + ψ ∘L h.symm.projectionOnto + +@[simp] +theorem coe_ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : + (ofIsTopCompl h φ ψ : E →ₗ[R] F) = LinearMap.ofIsCompl h.isCompl φ ψ := by + rw [LinearMap.ofIsCompl_eq_add] + rfl + +@[simp] +theorem ofIsTopCompl_apply_left (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) (x : p) : + ofIsTopCompl h φ ψ (x : E) = φ x := by + simp [ofIsTopCompl] + +@[simp] +theorem ofIsTopCompl_apply_right (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) (x : q) : + ofIsTopCompl h φ ψ (x : E) = ψ x := by + simp [ofIsTopCompl] + +theorem ofIsTopCompl_eq (h : IsTopCompl p q) {φ : p →L[R] F} {ψ : q →L[R] F} {χ : E →L[R] F} + (hφ : ∀ u : p, φ u = χ u) (hψ : ∀ u : q, ψ u = χ u) : ofIsTopCompl h φ ψ = χ := by + ext x + obtain ⟨_, _, rfl, _⟩ := existsUnique_add_of_isCompl h.isCompl x + simp [hφ, hψ] + +@[simp] +theorem ofIsTopCompl_zero (h : IsTopCompl p q) : + (ofIsTopCompl h 0 0 : E →L[R] F) = 0 := by + ext; simp [ofIsTopCompl] + +@[simp] +theorem ofIsTopCompl_add (h : IsTopCompl p q) (φ₁ φ₂ : p →L[R] F) (ψ₁ ψ₂ : q →L[R] F) : + ofIsTopCompl h (φ₁ + φ₂) (ψ₁ + ψ₂) = ofIsTopCompl h φ₁ ψ₁ + ofIsTopCompl h φ₂ ψ₂ := by + ext; simp [ofIsTopCompl]; abel + +@[simp] +theorem range_ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : + LinearMap.range (ofIsTopCompl h φ ψ : E →ₗ[R] F) = φ.range ⊔ ψ.range := by + rw [coe_ofIsTopCompl] + exact LinearMap.range_ofIsCompl h.isCompl + +end ContinuousLinearMap From d67a851898f8f6ce3b25cb7c36f1a50eb80673b7 Mon Sep 17 00:00:00 2001 From: sharky564 Date: Sat, 2 May 2026 21:53:27 +1000 Subject: [PATCH 049/210] Simplified proof --- Mathlib/Topology/Algebra/Module/Complement.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 6e9dd0dd70342a..3e4987eb535ea2 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -443,7 +443,7 @@ theorem ofIsTopCompl_zero (h : IsTopCompl p q) : @[simp] theorem ofIsTopCompl_add (h : IsTopCompl p q) (φ₁ φ₂ : p →L[R] F) (ψ₁ ψ₂ : q →L[R] F) : ofIsTopCompl h (φ₁ + φ₂) (ψ₁ + ψ₂) = ofIsTopCompl h φ₁ ψ₁ + ofIsTopCompl h φ₂ ψ₂ := by - ext; simp [ofIsTopCompl]; abel + ext; simp [ofIsTopCompl, add_add_add_comm] @[simp] theorem range_ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : From 0d6b87019fe2cf9232beb60e39b8f1a25d70fe52 Mon Sep 17 00:00:00 2001 From: sharky564 Date: Sat, 2 May 2026 22:38:57 +1000 Subject: [PATCH 050/210] Added top compl for complete space --- Mathlib/Analysis/Normed/Module/Complemented.lean | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Mathlib/Analysis/Normed/Module/Complemented.lean b/Mathlib/Analysis/Normed/Module/Complemented.lean index 9e92be0d1137c1..099f7b396229f4 100644 --- a/Mathlib/Analysis/Normed/Module/Complemented.lean +++ b/Mathlib/Analysis/Normed/Module/Complemented.lean @@ -108,6 +108,11 @@ theorem ClosedComplemented.of_isCompl_isClosed (h : IsCompl p q) (hp : IsClosed alias IsCompl.closedComplemented_of_isClosed := ClosedComplemented.of_isCompl_isClosed +theorem IsCompl.isTopCompl_of_isClosed (h : IsCompl p q) (hp : IsClosed (p : Set E)) + (hq : IsClosed (q : Set E)) : IsTopCompl p q := by + rw [h.isTopCompl_iff_isHomeomorph_prodEquiv] + exact (Submodule.prodEquivOfClosedCompl p q h hp hq).toHomeomorph.isHomeomorph + theorem closedComplemented_iff_isClosed_exists_isClosed_isCompl : p.ClosedComplemented ↔ IsClosed (p : Set E) ∧ ∃ q : Submodule 𝕜 E, IsClosed (q : Set E) ∧ IsCompl p q := From 888a55d57c7145d20f09d12b73d26241db214a5a Mon Sep 17 00:00:00 2001 From: sharky564 Date: Wed, 13 May 2026 01:29:06 +1000 Subject: [PATCH 051/210] Ported work over --- .../Topology/Algebra/Module/Complement.lean | 125 +++++++++++++++--- 1 file changed, 108 insertions(+), 17 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 3e4987eb535ea2..9ede93a9d48b04 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2026 Anatole Dedecker. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Anatole Dedecker +Authors: Anatole Dedecker, Sharvil Kesarwani -/ module @@ -29,14 +29,20 @@ change to something less misleading. to the definition given above. * `Submodule.ClosedComplemented`: we say that a submodule is (topologically) *complemented* if there exists a continuous projection `M →ₗ[R] p`. -* `Submodule.IsTopCompl.projectionOnto`: if `h : IsTopCompl p q`, `h.projectionOnto` is the +* `Submodule.IsTopCompl.projectionOntoL`: if `h : IsTopCompl p q`, `p.projectionOntoL q h` is the continuous linear projection `M →L[R] p` along `q`. This is the continuous version of - `Submodule.linearProjOfIsCompl`. -* `Submodule.IsTopCompl.projection`: if `h : IsTopCompl p q`, `h.projection` is the continuous + `Submodule.projectionOnto`. +* `Submodule.IsTopCompl.projectionL`: if `h : IsTopCompl p q`, `p.projectionL q h` is the continuous linear projection `M →L[R] M` onto `p` along `q`. This is the continuous version of `Submodule.IsCompl.projection`. * `Submodule.ClosedComplemented.complement`: an arbitrary topological complement of a topologically complemented submodule. +* `Submodule.IsTopCompl.prodEquiv`: the bundled continuous linear equivalence `p × q ≃L[R] M` + arising from a topological complement pair. +* `Submodule.IsTopCompl.quotientEquiv`: the bundled continuous linear equivalence `M ⧸ p ≃L[R] q` + arising from a topological complement pair. +* `ContinuousLinearMap.ofIsTopCompl`: the continuous linear map induced by maps on a topological + complement pair. ## Main statements @@ -55,18 +61,6 @@ Because the condition is symmetric, a lot of lemmas could have a left and a righ In general we only include the left version, the right one being accessible through `Submodule.IsTopCompl.symm`. -## TODO - -There is still a significant part of the algebraic API which should be ported to the -topological setting. Notably, we should: -* show that `Submodule.prodEquivOfIsCompl` is an homeomorphism if and only if - the two subspaces are topological complements, and bundle it as a `ContinuousLinearEquiv` when - this is the case. (See the existing `ClosedComplemented.exists_submodule_equiv_prod`). -* show that `Submodule.quotientEquivOfIsCompl` is an homeomorphism if and only if - the two subspaces are topological complements, and bundle it as a `ContinuousLinearEquiv` when - this is the case. -* define `ContinuousLinearMap.ofIsTopCompl`, analogous to `LinearMap.ofIsCompl`. - -/ @[expose] public section @@ -399,6 +393,103 @@ lemma ClosedComplemented.exists_submodule_equiv_prod [IsTopologicalAddGroup M] end ClosedComplemented +section ContinuousLinearEquiv + +variable [IsTopologicalAddGroup M] + +/-- Two submodules `p` and `q` are topological complements if and only if the algebraic equivalence +`p.prodEquivOfIsCompl q h` is continuous in the inverse direction. -/ +theorem _root_.IsCompl.isTopCompl_iff_continuous_prodEquiv_symm (h : IsCompl p q) : + IsTopCompl p q ↔ Continuous (p.prodEquivOfIsCompl q h).symm := + ⟨fun hTop ↦ ((p.projectionOntoL q hTop).prod (q.projectionOntoL p hTop.symm)).continuous.congr + fun x ↦ (prodEquivOfIsCompl_symm_apply h x).symm, + fun hCont ↦ ⟨h, continuous_subtype_val.comp <| continuous_fst.comp hCont⟩⟩ + +/-- The algebraic equivalence `p.prodEquivOfIsCompl q h : p × q ≃ₗ[R] M` from a pair of +complementary submodules is always continuous as a map `p × q → M`. -/ +theorem continuous_prodEquivOfIsCompl (h : IsCompl p q) : + Continuous (p.prodEquivOfIsCompl q h) := + (continuous_subtype_val.comp continuous_fst).add (continuous_subtype_val.comp continuous_snd) + +/-- Two submodules `p` and `q` are topological complements if and only if the algebraic equivalence +`p.prodEquivOfIsCompl q h` is a homeomorphism. -/ +theorem _root_.IsCompl.isTopCompl_iff_isHomeomorph_prodEquiv (h : IsCompl p q) : + IsTopCompl p q ↔ IsHomeomorph (p.prodEquivOfIsCompl q h) := by + rw [(p.prodEquivOfIsCompl q h).isHomeomorph_iff, h.isTopCompl_iff_continuous_prodEquiv_symm, + and_iff_right] + exact continuous_prodEquivOfIsCompl h + +/-- If two submodules `p` and `q` are topological complements, then the algebraic equivalence +`p.prodEquivOfIsCompl q h.isCompl` is a homeomorphism, bundled as a continuous linear equivalence. +-/ +noncomputable def IsTopCompl.prodEquiv (h : IsTopCompl p q) : (p × q) ≃L[R] M := + { p.prodEquivOfIsCompl q h.isCompl with + continuous_toFun := continuous_prodEquivOfIsCompl h.isCompl + continuous_invFun := h.isCompl.isTopCompl_iff_continuous_prodEquiv_symm.mp h } + +@[simp] +theorem IsTopCompl.coe_prodEquiv (h : IsTopCompl p q) : + (h.prodEquiv : (p × q) →ₗ[R] M) = p.prodEquivOfIsCompl q h.isCompl := + rfl + +@[simp] +theorem IsTopCompl.coe_prodEquiv_symm (h : IsTopCompl p q) : + (h.prodEquiv.symm : M →ₗ[R] p × q) = (p.prodEquivOfIsCompl q h.isCompl).symm := + rfl + +@[simp] +theorem IsTopCompl.prodEquiv_apply (h : IsTopCompl p q) (x : p × q) : + h.prodEquiv x = (x.1 : M) + x.2 := + rfl + +@[simp] +theorem IsTopCompl.prodEquiv_symm_apply (h : IsTopCompl p q) (x : M) : + h.prodEquiv.symm x = ((p.projectionOntoL q h x, q.projectionOntoL p h.symm x) : p × q) := + prodEquivOfIsCompl_symm_apply h.isCompl x + +/-- Two submodules `p` and `q` are topological complements if and only if the algebraic equivalence +`p.quotientEquivOfIsCompl q h` is continuous. -/ +theorem IsCompl.isTopCompl_iff_continuous_quotientEquiv (h : IsCompl p q) : + IsTopCompl p q ↔ Continuous (p.quotientEquivOfIsCompl q h) := by + have hproj : ⇑(p.quotientEquivOfIsCompl q h) ∘ ⇑p.mkQ = ⇑(q.projectionOnto p h.symm) := by + funext; simp + rw [p.isQuotientMap_mkQL.continuous_iff, coe_mkQL, hproj, ← h.symm.isTopCompl_iff_projectionOnto] + exact ⟨IsTopCompl.symm, IsTopCompl.symm⟩ + +/-- If two submodules `p` and `q` are topological complements, then the algebraic equivalence +`p.quotientEquivOfIsCompl q h.isCompl` is a homeomorphism, bundled as a continuous linear +equivalence. -/ +noncomputable def IsTopCompl.quotientEquiv (h : IsTopCompl p q) : (M ⧸ p) ≃L[R] q := + { p.quotientEquivOfIsCompl q h.isCompl with + continuous_toFun := (h.isCompl.isTopCompl_iff_continuous_quotientEquiv).mp h + continuous_invFun := (p.mkQL.comp q.subtypeL).continuous } + +@[simp] +theorem IsTopCompl.coe_quotientEquiv (h : IsTopCompl p q) : + (h.quotientEquiv : (M ⧸ p) →ₗ[R] q) = p.quotientEquivOfIsCompl q h.isCompl := + rfl + +@[simp] +theorem IsTopCompl.coe_quotientEquiv_symm (h : IsTopCompl p q) : + (h.quotientEquiv.symm : q →ₗ[R] M ⧸ p) = (p.quotientEquivOfIsCompl q h.isCompl).symm := + rfl + +theorem IsTopCompl.quotientEquiv_apply (h : IsTopCompl p q) (x : M ⧸ p) : + h.quotientEquiv x = p.quotientEquivOfIsCompl q h.isCompl x := + rfl + +@[simp] +theorem IsTopCompl.quotientEquiv_symm_apply (h : IsTopCompl p q) (y : q) : + h.quotientEquiv.symm y = p.mkQ y := + rfl + +@[simp] +theorem IsTopCompl.quotientEquiv_apply_mk (h : IsTopCompl p q) (x : M) : + h.quotientEquiv (Submodule.Quotient.mk x) = q.projectionOnto p h.isCompl.symm x := + quotientEquivOfIsCompl_apply_mk h.isCompl x + +end ContinuousLinearEquiv + end Submodule namespace ContinuousLinearMap @@ -411,7 +502,7 @@ variable {R : Type*} [Ring R] {E F : Type*} /-- Given continuous linear maps `φ : p →L[R] F` and `ψ : q →L[R] F` from topological complement submodules of `E`, the induced continuous linear map `E →L[R] F`. -/ noncomputable def ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : E →L[R] F := - φ ∘L h.projectionOnto + ψ ∘L h.symm.projectionOnto + φ ∘L p.projectionOntoL q h + ψ ∘L q.projectionOntoL p h.symm @[simp] theorem coe_ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : From dd74e447739e2f8e8385a69115c96751d42a8311 Mon Sep 17 00:00:00 2001 From: sharky564 Date: Wed, 13 May 2026 01:43:07 +1000 Subject: [PATCH 052/210] Removed unnecessary --- Mathlib/Analysis/Normed/Module/Complemented.lean | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Mathlib/Analysis/Normed/Module/Complemented.lean b/Mathlib/Analysis/Normed/Module/Complemented.lean index 099f7b396229f4..9e92be0d1137c1 100644 --- a/Mathlib/Analysis/Normed/Module/Complemented.lean +++ b/Mathlib/Analysis/Normed/Module/Complemented.lean @@ -108,11 +108,6 @@ theorem ClosedComplemented.of_isCompl_isClosed (h : IsCompl p q) (hp : IsClosed alias IsCompl.closedComplemented_of_isClosed := ClosedComplemented.of_isCompl_isClosed -theorem IsCompl.isTopCompl_of_isClosed (h : IsCompl p q) (hp : IsClosed (p : Set E)) - (hq : IsClosed (q : Set E)) : IsTopCompl p q := by - rw [h.isTopCompl_iff_isHomeomorph_prodEquiv] - exact (Submodule.prodEquivOfClosedCompl p q h hp hq).toHomeomorph.isHomeomorph - theorem closedComplemented_iff_isClosed_exists_isClosed_isCompl : p.ClosedComplemented ↔ IsClosed (p : Set E) ∧ ∃ q : Submodule 𝕜 E, IsClosed (q : Set E) ∧ IsCompl p q := From 84a1836cc39fc73f32e06ef91e82c26ef7e984e5 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 12 May 2026 14:59:44 -0400 Subject: [PATCH 053/210] ++ --- Mathlib/Data/Setoid/Basic.lean | 8 +++ Mathlib/Logic/Equiv/Quotient.lean | 37 ------------- Mathlib/Topology/Constructions.lean | 6 +++ Mathlib/Topology/Homeomorph/Quotient.lean | 64 +++++++++++++++++++++++ 4 files changed, 78 insertions(+), 37 deletions(-) delete mode 100644 Mathlib/Logic/Equiv/Quotient.lean create mode 100644 Mathlib/Topology/Homeomorph/Quotient.lean diff --git a/Mathlib/Data/Setoid/Basic.lean b/Mathlib/Data/Setoid/Basic.lean index edb9c8209339df..0547b8285f1049 100644 --- a/Mathlib/Data/Setoid/Basic.lean +++ b/Mathlib/Data/Setoid/Basic.lean @@ -228,6 +228,14 @@ def map_sInf {S : Set (Setoid α)} {s : Setoid α} (h : s ∈ S) : Quotient (sInf S) → Quotient s := Setoid.map_of_le fun _ _ a ↦ a s h +/-- The quotient by the trivial relation is equivalent to the original space. -/ +def quotientBotEquiv : + Quotient (⊥ : Setoid α) ≃ α where + toFun := Quotient.lift id (fun _ _ ↦ id) + invFun := Quotient.mk'' + left_inv := Quotient.ind fun _ ↦ rfl + right_inv := fun _ ↦ rfl + section EqvGen open Relation diff --git a/Mathlib/Logic/Equiv/Quotient.lean b/Mathlib/Logic/Equiv/Quotient.lean deleted file mode 100644 index 8b7c368b79e211..00000000000000 --- a/Mathlib/Logic/Equiv/Quotient.lean +++ /dev/null @@ -1,37 +0,0 @@ -/- -Copyright (c) 2026 Anatole Dedecker. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Anatole Dedecker --/ -module - -public import Mathlib.Data.Set.Function -public import Mathlib.Logic.Equiv.Defs - -/-! -# Equivalences and quotients - -In this file we provide facts relating `Equiv` and `Quotient`. --/ - -@[expose] public section - -open Function Set - -variable {α β γ : Type*} - -namespace Equiv - -@[simps] -protected def quotCongr {r s : α → α → Prop} (eq : r = s) : Quot r ≃ Quot s where - toFun := Quot.lift (Quot.mk s) (by simp [eq, Quot.congr_mk]) - invFun := sorry - left_inv := sorry - right_inv := sorry - -/-- If `α` is equivalent to `β`, then `Set α` is equivalent to `Set β`. -/ -@[simps] -protected def congr {α β : Type*} (e : α ≃ β) : Set α ≃ Set β := - ⟨fun s => e '' s, fun t => e.symm '' t, symm_image_image e, symm_image_image e.symm⟩ - -end Equiv diff --git a/Mathlib/Topology/Constructions.lean b/Mathlib/Topology/Constructions.lean index 6f88474bbad152..86330aca6eaff4 100644 --- a/Mathlib/Topology/Constructions.lean +++ b/Mathlib/Topology/Constructions.lean @@ -702,6 +702,12 @@ theorem continuous_quot_lift {f : X → Y} (hr : ∀ a b, r a b → f a = f b) ( Continuous (Quot.lift f hr : Quot r → Y) := continuous_coinduced_dom.2 h +@[continuity, fun_prop] +theorem continuous_quot_map {r' : Y → Y → Prop} {f : X → Y} (hr : ∀ a b, r a b → r' (f a) (f b)) + (h : Continuous f) : + Continuous (Quot.map f hr : Quot r → Quot r') := + continuous_quot_lift _ (continuous_quot_mk.comp h) + theorem isQuotientMap_quotient_mk' : IsQuotientMap (@Quotient.mk' X s) := isQuotientMap_quot_mk diff --git a/Mathlib/Topology/Homeomorph/Quotient.lean b/Mathlib/Topology/Homeomorph/Quotient.lean new file mode 100644 index 00000000000000..c27063394665c7 --- /dev/null +++ b/Mathlib/Topology/Homeomorph/Quotient.lean @@ -0,0 +1,64 @@ +/- +Copyright (c) 2026 Anatole Dedecker. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Anatole Dedecker +-/ +module + +public import Mathlib.Topology.Homeomorph.Lemmas + +/-! +# Homeomorphisms between quotient spaces +-/ + +@[expose] public section + +namespace Homeomorph + +variable {α β : Type*} [TopologicalSpace α] [TopologicalSpace β] + +namespace Quot + +/-- An homeomorphism `e : α ≃ₜ β` generates an homeomorphism between quotient spaces, +if `ra a₁ a₂ ↔ rb (e a₁) (e a₂)`. -/ +protected def congr {ra : α → α → Prop} {rb : β → β → Prop} (e : α ≃ₜ β) + (eq : ∀ a₁ a₂, ra a₁ a₂ ↔ rb (e a₁) (e a₂)) : Quot ra ≃ₜ Quot rb where + toEquiv := _root_.Quot.congr e eq + continuous_toFun := continuous_quot_map (fun x y ↦ by simp [eq]) e.continuous + continuous_invFun := continuous_quot_map (fun x y ↦ by simp [eq]) e.symm.continuous + +/-- Quotient spaces for equal relations are homeomorphic. -/ +protected def congrRight {r r' : α → α → Prop} (eq : ∀ a₁ a₂, r a₁ a₂ ↔ r' a₁ a₂) : + Quot r ≃ₜ Quot r' := Quot.congr (Homeomorph.refl α) eq + +/-- An homeomorphism `e : α ≃ₜ β` generates an equivalence between the quotient space of `α` +by a relation `ra` and the quotient space of `β` by the image of this relation under `e`. -/ +protected def congrLeft {r : α → α → Prop} (e : α ≃ₜ β) : + Quot r ≃ₜ Quot fun b b' => r (e.symm b) (e.symm b') := + Quot.congr e fun _ _ => by simp only [e.symm_apply_apply] + +end Quot + +namespace Quotient + +/-- An homeomorphism `e : α ≃ₜ β` generates an homeomorphism between quotient spaces, +if `ra a₁ a₂ ↔ rb (e a₁) (e a₂)`. -/ +protected def congr {ra : Setoid α} {rb : Setoid β} (e : α ≃ₜ β) + (eq : ∀ a₁ a₂, ra a₁ a₂ ↔ rb (e a₁) (e a₂)) : + Quotient ra ≃ₜ Quotient rb := Quot.congr e eq + +/-- Quotient spaces for equal relations are homeomorphic. -/ +protected def congrRight {r r' : Setoid α} + (eq : ∀ a₁ a₂, r a₁ a₂ ↔ r' a₁ a₂) : Quotient r ≃ₜ Quotient r' := + Quot.congrRight eq + +end Quotient + +/-- The quotient by the trivial relation is homeomorphic to the original space. -/ +def quotientBot : + Quotient (⊥ : Setoid α) ≃ₜ α where + toEquiv := Setoid.quotientBotEquiv + continuous_toFun := continuous_quot_lift _ continuous_id + continuous_invFun := continuous_quot_mk + +end Homeomorph From 1f1edaab0335c6d1b5f847b0cda657c75005977d Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 12 May 2026 15:03:07 -0400 Subject: [PATCH 054/210] mk_all --- Mathlib.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/Mathlib.lean b/Mathlib.lean index 4460548cdfeedf..2f45e6efa2056b 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -7714,6 +7714,7 @@ public import Mathlib.Topology.Hom.ContinuousEvalConst public import Mathlib.Topology.Hom.Open public import Mathlib.Topology.Homeomorph.Defs public import Mathlib.Topology.Homeomorph.Lemmas +public import Mathlib.Topology.Homeomorph.Quotient public import Mathlib.Topology.Homeomorph.TransferInstance public import Mathlib.Topology.Homotopy.Affine public import Mathlib.Topology.Homotopy.Basic From 2c7958b427f12bb412915db4e90a23a254ce6935 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 12 May 2026 16:11:23 -0400 Subject: [PATCH 055/210] suggestions --- Mathlib/Topology/Homeomorph/Quotient.lean | 38 +++++++++++------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Mathlib/Topology/Homeomorph/Quotient.lean b/Mathlib/Topology/Homeomorph/Quotient.lean index c27063394665c7..85363c4f59a2d5 100644 --- a/Mathlib/Topology/Homeomorph/Quotient.lean +++ b/Mathlib/Topology/Homeomorph/Quotient.lean @@ -15,40 +15,40 @@ public import Mathlib.Topology.Homeomorph.Lemmas namespace Homeomorph -variable {α β : Type*} [TopologicalSpace α] [TopologicalSpace β] +variable {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] namespace Quot -/-- An homeomorphism `e : α ≃ₜ β` generates an homeomorphism between quotient spaces, -if `ra a₁ a₂ ↔ rb (e a₁) (e a₂)`. -/ -protected def congr {ra : α → α → Prop} {rb : β → β → Prop} (e : α ≃ₜ β) - (eq : ∀ a₁ a₂, ra a₁ a₂ ↔ rb (e a₁) (e a₂)) : Quot ra ≃ₜ Quot rb where +/-- An homeomorphism `e : X ≃ₜ Y` generXtes an homeomorphism between quotient spaces, +if `rX a₁ a₂ ↔ rY (e a₁) (e a₂)`. -/ +protected def congr {rX : X → X → Prop} {rY : Y → Y → Prop} (e : X ≃ₜ Y) + (eq : ∀ a₁ a₂, rX a₁ a₂ ↔ rY (e a₁) (e a₂)) : Quot rX ≃ₜ Quot rY where toEquiv := _root_.Quot.congr e eq continuous_toFun := continuous_quot_map (fun x y ↦ by simp [eq]) e.continuous continuous_invFun := continuous_quot_map (fun x y ↦ by simp [eq]) e.symm.continuous /-- Quotient spaces for equal relations are homeomorphic. -/ -protected def congrRight {r r' : α → α → Prop} (eq : ∀ a₁ a₂, r a₁ a₂ ↔ r' a₁ a₂) : - Quot r ≃ₜ Quot r' := Quot.congr (Homeomorph.refl α) eq +protected def congrRight {r r' : X → X → Prop} (eq : ∀ a₁ a₂, r a₁ a₂ ↔ r' a₁ a₂) : + Quot r ≃ₜ Quot r' := Quot.congr (Homeomorph.refl X) eq -/-- An homeomorphism `e : α ≃ₜ β` generates an equivalence between the quotient space of `α` -by a relation `ra` and the quotient space of `β` by the image of this relation under `e`. -/ -protected def congrLeft {r : α → α → Prop} (e : α ≃ₜ β) : - Quot r ≃ₜ Quot fun b b' => r (e.symm b) (e.symm b') := - Quot.congr e fun _ _ => by simp only [e.symm_apply_apply] +/-- An homeomorphism `e : X ≃ₜ Y` generXtes an equivalence between the quotient space of `X` +by a relation `rX` and the quotient space of `Y` by the image of this relation under `e`. -/ +protected def congrLeft {r : X → X → Prop} (e : X ≃ₜ Y) : + Quot r ≃ₜ Quot fun b b' ↦ r (e.symm b) (e.symm b') := + Quot.congr e fun _ _ ↦ by simp only [e.symm_apply_apply] end Quot namespace Quotient -/-- An homeomorphism `e : α ≃ₜ β` generates an homeomorphism between quotient spaces, -if `ra a₁ a₂ ↔ rb (e a₁) (e a₂)`. -/ -protected def congr {ra : Setoid α} {rb : Setoid β} (e : α ≃ₜ β) - (eq : ∀ a₁ a₂, ra a₁ a₂ ↔ rb (e a₁) (e a₂)) : - Quotient ra ≃ₜ Quotient rb := Quot.congr e eq +/-- An homeomorphism `e : X ≃ₜ Y` generXtes an homeomorphism between quotient spaces, +if `rX a₁ a₂ ↔ rY (e a₁) (e a₂)`. -/ +protected def congr {rX : Setoid X} {rY : Setoid Y} (e : X ≃ₜ Y) + (eq : ∀ a₁ a₂, rX a₁ a₂ ↔ rY (e a₁) (e a₂)) : + Quotient rX ≃ₜ Quotient rY := Quot.congr e eq /-- Quotient spaces for equal relations are homeomorphic. -/ -protected def congrRight {r r' : Setoid α} +protected def congrRight {r r' : Setoid X} (eq : ∀ a₁ a₂, r a₁ a₂ ↔ r' a₁ a₂) : Quotient r ≃ₜ Quotient r' := Quot.congrRight eq @@ -56,7 +56,7 @@ end Quotient /-- The quotient by the trivial relation is homeomorphic to the original space. -/ def quotientBot : - Quotient (⊥ : Setoid α) ≃ₜ α where + Quotient (⊥ : Setoid X) ≃ₜ X where toEquiv := Setoid.quotientBotEquiv continuous_toFun := continuous_quot_lift _ continuous_id continuous_invFun := continuous_quot_mk From afdcf3784a5409e7019ca1ef338e4dec6f4dee7d Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 12 May 2026 16:12:53 -0400 Subject: [PATCH 056/210] var names --- Mathlib/Topology/Homeomorph/Quotient.lean | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Mathlib/Topology/Homeomorph/Quotient.lean b/Mathlib/Topology/Homeomorph/Quotient.lean index 85363c4f59a2d5..5091da4c6fefe1 100644 --- a/Mathlib/Topology/Homeomorph/Quotient.lean +++ b/Mathlib/Topology/Homeomorph/Quotient.lean @@ -20,21 +20,21 @@ variable {X Y : Type*} [TopologicalSpace X] [TopologicalSpace Y] namespace Quot /-- An homeomorphism `e : X ≃ₜ Y` generXtes an homeomorphism between quotient spaces, -if `rX a₁ a₂ ↔ rY (e a₁) (e a₂)`. -/ +if `rX x₁ x₂ ↔ rY (e x₁) (e x₂)`. -/ protected def congr {rX : X → X → Prop} {rY : Y → Y → Prop} (e : X ≃ₜ Y) - (eq : ∀ a₁ a₂, rX a₁ a₂ ↔ rY (e a₁) (e a₂)) : Quot rX ≃ₜ Quot rY where + (eq : ∀ x₁ x₂, rX x₁ x₂ ↔ rY (e x₁) (e x₂)) : Quot rX ≃ₜ Quot rY where toEquiv := _root_.Quot.congr e eq continuous_toFun := continuous_quot_map (fun x y ↦ by simp [eq]) e.continuous continuous_invFun := continuous_quot_map (fun x y ↦ by simp [eq]) e.symm.continuous /-- Quotient spaces for equal relations are homeomorphic. -/ -protected def congrRight {r r' : X → X → Prop} (eq : ∀ a₁ a₂, r a₁ a₂ ↔ r' a₁ a₂) : +protected def congrRight {r r' : X → X → Prop} (eq : ∀ x₁ x₂, r x₁ x₂ ↔ r' x₁ x₂) : Quot r ≃ₜ Quot r' := Quot.congr (Homeomorph.refl X) eq /-- An homeomorphism `e : X ≃ₜ Y` generXtes an equivalence between the quotient space of `X` by a relation `rX` and the quotient space of `Y` by the image of this relation under `e`. -/ protected def congrLeft {r : X → X → Prop} (e : X ≃ₜ Y) : - Quot r ≃ₜ Quot fun b b' ↦ r (e.symm b) (e.symm b') := + Quot r ≃ₜ Quot fun y₁ y₂ ↦ r (e.symm y₁) (e.symm y₂) := Quot.congr e fun _ _ ↦ by simp only [e.symm_apply_apply] end Quot @@ -42,14 +42,14 @@ end Quot namespace Quotient /-- An homeomorphism `e : X ≃ₜ Y` generXtes an homeomorphism between quotient spaces, -if `rX a₁ a₂ ↔ rY (e a₁) (e a₂)`. -/ +if `rX x₁ x₂ ↔ rY (e x₁) (e x₂)`. -/ protected def congr {rX : Setoid X} {rY : Setoid Y} (e : X ≃ₜ Y) - (eq : ∀ a₁ a₂, rX a₁ a₂ ↔ rY (e a₁) (e a₂)) : + (eq : ∀ x₁ x₂, rX x₁ x₂ ↔ rY (e x₁) (e x₂)) : Quotient rX ≃ₜ Quotient rY := Quot.congr e eq /-- Quotient spaces for equal relations are homeomorphic. -/ protected def congrRight {r r' : Setoid X} - (eq : ∀ a₁ a₂, r a₁ a₂ ↔ r' a₁ a₂) : Quotient r ≃ₜ Quotient r' := + (eq : ∀ x₁ x₂, r x₁ x₂ ↔ r' x₁ x₂) : Quotient r ≃ₜ Quotient r' := Quot.congrRight eq end Quotient From 85d84bbafc0f6b96e0c89b83b9bffa70996c9bfe Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 12 May 2026 16:39:28 -0400 Subject: [PATCH 057/210] Done! --- Mathlib/Topology/Maps/Strict/Basic.lean | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index 955c3d37f8a1bb..5532ff0e0f98ef 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -6,14 +6,14 @@ Authors: Ziyan Wei module public import Mathlib.Topology.Maps.Basic -public import Mathlib.Topology.Homeomorph.Lemmas +public import Mathlib.Topology.Homeomorph.Quotient public import Mathlib.Topology.Constructions public import Mathlib.Data.Setoid.Basic /-! # Bourbaki Strict Maps This file defines Bourbaki strict maps (`Topology.IsStrictMap`) and proves some of their -basic properties. ? +basic properties. A map `f : X → Y` between topological spaces is called *strict* in the sense of Bourbaki if the natural corestriction to its image (i.e., `Set.rangeFactorization f`) is a quotient map. @@ -37,7 +37,7 @@ We provide several equivalent ways to characterize a strict map `f`: @[expose] public section -open Function Set Topology +open Function Set Topology Setoid namespace Topology @@ -116,9 +116,13 @@ lemma IsQuotientMap.isStrictMap (f_quot : IsQuotientMap f) : lemma IsEmbedding.isStrictMap_iff (g_emb : IsEmbedding g) : IsStrictMap f ↔ IsStrictMap (g ∘ f) := by - have eq : Setoid.ker (g ∘ f) = Setoid.ker f := by ext; simp [g_emb.injective.eq_iff] - rw [isStrictMap_iff_isEmbedding_kerLift, isStrictMap_iff_isEmbedding_kerLift] - sorry + set Φ : Quotient (Setoid.ker (g ∘ f)) ≃ₜ Quotient (Setoid.ker (f)) := + Homeomorph.Quotient.congrRight (fun _ _ ↦ by simp [g_emb.injective.eq_iff]) + have key : g ∘ kerLift f ∘ Φ = kerLift (g ∘ f) := + funext <| Quotient.ind fun _ ↦ rfl + simp_rw [isStrictMap_iff_isEmbedding_kerLift, ← g_emb.of_comp_iff, ← key] + exact ⟨fun H ↦ H.comp Φ.isEmbedding, + fun H ↦ by simpa [comp_assoc] using H.comp Φ.symm.isEmbedding⟩ lemma IsEmbedding.isStrictMap (f_emb : IsEmbedding f) : IsStrictMap f := @@ -134,6 +138,9 @@ lemma isQuotientMap_iff_isStrictMap_surjective : lemma isEmbedding_iff_isStrictMap_injective : IsEmbedding f ↔ IsStrictMap f ∧ Injective f := by refine ⟨fun H ↦ ⟨H.isStrictMap, H.injective⟩, fun ⟨f_strict, f_inj⟩ ↦ ?_⟩ - sorry + rw [isStrictMap_iff_isEmbedding_kerLift] at f_strict + set Φ : Quotient (ker f) ≃ₜ X := + (Homeomorph.Quotient.congrRight <| by simp [f_inj.eq_iff]).trans Homeomorph.quotientBot + exact f_strict.comp Φ.symm.isEmbedding end Topology From 244808e3bd19b018e73d7279b685e79441ca1d1d Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 12 May 2026 16:50:22 -0400 Subject: [PATCH 058/210] Comments --- Mathlib/Topology/Maps/Strict/Basic.lean | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index 5532ff0e0f98ef..83bae8f4523efb 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2026 Ziyan Wei. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Ziyan Wei +Authors: Ziyan Wei, Anatole Dedecker -/ module @@ -97,12 +97,16 @@ lemma IsClosedMap.isStrictMap (hc : IsClosedMap f) (h_cont : Continuous f) : exact (hc.subtype_mk fun x => ⟨x, rfl⟩).isQuotientMap h_cont.rangeFactorization Set.rangeFactorization_surjective +/-- A homeomorphism is a strict map. -/ lemma IsHomeomorph.isStrictMap (f_homeo : IsHomeomorph f) : IsStrictMap f := f_homeo.isOpenMap.isStrictMap f_homeo.continuous +/-- The identity is a strict map. -/ lemma IsStrictMap.id : IsStrictMap (id : X → X) := IsHomeomorph.id.isStrictMap +/-- Assume that `f : X → Y` is a quotient map. Then `g : Y → Z` is strict +if and only if `g ∘ f` is strict. -/ lemma IsQuotientMap.isStrictMap_iff (f_quot : IsQuotientMap f) : IsStrictMap g ↔ IsStrictMap (g ∘ f) := by set Φ : range (g ∘ f) ≃ₜ range g := .setCongr <| f_quot.surjective.range_comp g @@ -110,10 +114,13 @@ lemma IsQuotientMap.isStrictMap_iff (f_quot : IsQuotientMap f) : simp_rw [isStrictMap_iff_isQuotientMap_rangeFactorization, ← f_quot.of_comp_iff, key] exact ⟨fun H ↦ by simpa using Φ.symm.isQuotientMap.comp H, fun H ↦ Φ.isQuotientMap.comp H⟩ +/-- A quotient map is strict. See also `isQuotientMap_iff_isStrictMap_surjective`. -/ lemma IsQuotientMap.isStrictMap (f_quot : IsQuotientMap f) : IsStrictMap f := f_quot.isStrictMap_iff.mp .id +/-- Assume that `g : Y → Z` is an embedding. Then `f : X → Y` is strict +if and only if `g ∘ f` is strict. -/ lemma IsEmbedding.isStrictMap_iff (g_emb : IsEmbedding g) : IsStrictMap f ↔ IsStrictMap (g ∘ f) := by set Φ : Quotient (Setoid.ker (g ∘ f)) ≃ₜ Quotient (Setoid.ker (f)) := @@ -124,10 +131,12 @@ lemma IsEmbedding.isStrictMap_iff (g_emb : IsEmbedding g) : exact ⟨fun H ↦ H.comp Φ.isEmbedding, fun H ↦ by simpa [comp_assoc] using H.comp Φ.symm.isEmbedding⟩ +/-- An embedding is strict. See also `isEmbedding_iff_isStrictMap_injective`. -/ lemma IsEmbedding.isStrictMap (f_emb : IsEmbedding f) : IsStrictMap f := f_emb.isStrictMap_iff.mp .id +/-- Quotient maps are precisely surjective strict maps. -/ lemma isQuotientMap_iff_isStrictMap_surjective : IsQuotientMap f ↔ IsStrictMap f ∧ Surjective f := by refine ⟨fun H ↦ ⟨H.isStrictMap, H.surjective⟩, fun ⟨f_strict, f_surj⟩ ↦ ?_⟩ @@ -135,6 +144,7 @@ lemma isQuotientMap_iff_isStrictMap_surjective : set Φ : range f ≃ₜ Y := .trans (.setCongr f_surj.range_eq) (Homeomorph.Set.univ Y) exact Φ.isQuotientMap.comp f_strict +/-- Embeddings are precisely injective strict maps. -/ lemma isEmbedding_iff_isStrictMap_injective : IsEmbedding f ↔ IsStrictMap f ∧ Injective f := by refine ⟨fun H ↦ ⟨H.isStrictMap, H.injective⟩, fun ⟨f_strict, f_inj⟩ ↦ ?_⟩ From 59fdf3f0c72c11c4c86645d3bcb51993e939fda5 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 12 May 2026 17:28:51 -0400 Subject: [PATCH 059/210] mk_all --- Mathlib.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/Mathlib.lean b/Mathlib.lean index c00e157f3a03ae..fb584626e3a5d4 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2196,6 +2196,7 @@ public import Mathlib.Analysis.Normed.Operator.LinearIsometry public import Mathlib.Analysis.Normed.Operator.Mul public import Mathlib.Analysis.Normed.Operator.NNNorm public import Mathlib.Analysis.Normed.Operator.NormedSpace +public import Mathlib.Analysis.Normed.Operator.Perturbation.StrictByFinite public import Mathlib.Analysis.Normed.Operator.Prod public import Mathlib.Analysis.Normed.Order.Basic public import Mathlib.Analysis.Normed.Order.Hom.Basic From daf79ec181d28761bfe7ce10514f7d1b4d3a8f23 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 12 May 2026 18:13:18 -0400 Subject: [PATCH 060/210] feat: continuous version of Submodule.liftQ --- .../Topology/Algebra/Module/LinearMap.lean | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/Mathlib/Topology/Algebra/Module/LinearMap.lean b/Mathlib/Topology/Algebra/Module/LinearMap.lean index 9e10ba35a06a14..dc32e49db94280 100644 --- a/Mathlib/Topology/Algebra/Module/LinearMap.lean +++ b/Mathlib/Topology/Algebra/Module/LinearMap.lean @@ -1264,7 +1264,9 @@ end Semiring section Ring -variable {R : Type*} [Ring R] {M : Type*} [TopologicalSpace M] [AddCommGroup M] [Module R M] +variable {R R₂ : Type*} [Ring R] [Ring R₂] {σ : R →+* R₂} {M M₂ : Type*} + [TopologicalSpace M] [AddCommGroup M] [Module R M] + [TopologicalSpace M₂] [AddCommGroup M₂] [Module R₂ M₂] (S : Submodule R M) open ContinuousLinearMap @@ -1287,6 +1289,24 @@ theorem isQuotientMap_mkQL : IsQuotientMap S.mkQL := isQuotientMap_quot_mk theorem isOpenQuotientMap_mkQL [ContinuousAdd M] : IsOpenQuotientMap S.mkQL := S.isOpenQuotientMap_mkQ +/-- `Submodule.mkQ` as a `ContinuousLinearMap`. -/ +def liftQL (f : M →SL[σ] M₂) (h : S ≤ f.ker) : M ⧸ S →SL[σ] M₂ where + toLinearMap := S.liftQ f h + cont := continuous_quot_lift _ f.continuous + +@[simp, norm_cast] +theorem toLinearMap_liftQL (f : M →SL[σ] M₂) (h : S ≤ f.ker) : + (S.liftQL f h).toLinearMap = S.liftQ f.toLinearMap h := rfl + +@[simp] +theorem coe_liftQL (f : M →SL[σ] M₂) (h : S ≤ f.ker) : + ⇑(S.liftQL f h) = S.liftQ f.toLinearMap h := + rfl + +theorem liftQL_apply (f : M →SL[σ] M₂) (h : S ≤ f.ker) (x : M ⧸ S) : + S.liftQL f h x = S.liftQ f.toLinearMap h x := by + simp + end Ring end Submodule From bea5ca55c00621a3a6a6adcf6276fda8a92ad251 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 12 May 2026 18:25:11 -0400 Subject: [PATCH 061/210] liftQL --- .../Normed/Operator/Perturbation/StrictByFinite.lean | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 00b1d63c621a67..9a1d431f040f88 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -57,10 +57,7 @@ theorem step1_foward (A : Submodule 𝕜 E) (K : Submodule 𝕜 E) (A_closed : I · rcases K_disj_A.exists_isCompl with ⟨S, K_le_S, S_compl_A⟩ replace S_compl_A : IsTopCompl S A := S_compl_A.symm.isTopCompl_of_finiteDimensional_quotient A_closed |>.symm - -- TODO: `Submodule.liftQL` - let s : E ⧸ K →L[𝕜] A := - ⟨K.liftQ (A.projectionOntoL S S_compl_A.symm) (by simpa), - continuous_quot_lift _ (A.projectionOntoL S S_compl_A.symm).continuous⟩ + let s : E ⧸ K →L[𝕜] A := K.liftQL (A.projectionOntoL S S_compl_A.symm) (by simpa) have leftInv : LeftInverse s (restrict A K.mkQ) := fun x ↦ by simp [s] refine .of_leftInverse leftInv s.continuous (by fun_prop) · rw [← K.isQuotientMap_mkQ.isClosed_preimage, range_restrict, ← Submodule.map_coe, @@ -106,8 +103,7 @@ a closed embedding. theorem step2_forward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_strict : IsStrictMap u) (h_closed : IsClosed (range u)) : IsClosedEmbedding (restrict A u) := by - -- TODO: `Submodule.liftQL` ? - let u' : E ⧸ u.ker →ₗ[𝕜] F := u.ker.liftQ u le_rfl + let u' : E ⧸ u.ker →L[𝕜] F := u.ker.liftQL u le_rfl have u'_clemb : IsClosedEmbedding u' := by constructor · sorry -- should be fixed with more API on strict homs @@ -151,7 +147,7 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict (u : (IsStrictMap u ∧ IsClosed (range u)) ↔ (IsStrictMap (restrict A u) ∧ IsClosed (u '' A)) := by set N : Submodule 𝕜 E := A ⊓ u.ker - set v : E ⧸ N →L[𝕜] F := ⟨N.liftQ u inf_le_right, continuous_quot_lift _ u.continuous⟩ + set v : E ⧸ N →L[𝕜] F := N.liftQL u inf_le_right have v_eq_u : v ∘L N.mkQL = u := rfl set B : Submodule 𝕜 (E ⧸ N) := map N.mkQ A have comap_B : comap N.mkQ B = A := by simp [B, N] From d21557d52b3d41098650223767520da3432b6254 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 12 May 2026 18:49:31 -0400 Subject: [PATCH 062/210] feat: `IsOpenQuotientMap.restrictPreimage` --- Mathlib/Topology/LocalAtTarget.lean | 6 ++++++ Mathlib/Topology/Maps/Strict/Basic.lean | 2 ++ 2 files changed, 8 insertions(+) diff --git a/Mathlib/Topology/LocalAtTarget.lean b/Mathlib/Topology/LocalAtTarget.lean index f82289f50e31c8..f638ce6fce4e0a 100644 --- a/Mathlib/Topology/LocalAtTarget.lean +++ b/Mathlib/Topology/LocalAtTarget.lean @@ -21,6 +21,8 @@ We show that the following properties of continuous maps are local at the target - `IsOpenEmbedding` - `IsClosedEmbedding` - `GeneralizingMap` +- `IsProperMap` +- `IsOpenQuotientMap` We show that the following properties of continuous maps are local at the source: - `IsOpenMap` @@ -94,6 +96,10 @@ lemma IsProperMap.restrictPreimage (H : IsProperMap f) (s : Set β) : rw [IsEmbedding.subtypeVal.isCompact_iff, image_val_preimage_restrictPreimage, image_singleton] exact H.isCompact_preimage isCompact_singleton +lemma IsOpenQuotientMap.restrictPreimage (H : IsOpenQuotientMap f) (s : Set β) : + IsOpenQuotientMap (s.restrictPreimage f) := + ⟨H.surjective.restrictPreimage _, H.continuous.restrictPreimage, H.isOpenMap.restrictPreimage _⟩ + namespace TopologicalSpace.IsOpenCover section LocalAtTarget diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index 83bae8f4523efb..5ced836d06011c 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -153,4 +153,6 @@ lemma isEmbedding_iff_isStrictMap_injective : (Homeomorph.Quotient.congrRight <| by simp [f_inj.eq_iff]).trans Homeomorph.quotientBot exact f_strict.comp Φ.symm.isEmbedding +#check IsOpenQuotientMap + end Topology From 6105a43841a1bfea3716226ec54e830589fcc740 Mon Sep 17 00:00:00 2001 From: sharky564 Date: Wed, 13 May 2026 23:02:03 +1000 Subject: [PATCH 063/210] Simp lint fixes --- Mathlib/Topology/Algebra/Module/Complement.lean | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 9ede93a9d48b04..fbde8b8391a382 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -536,10 +536,7 @@ theorem ofIsTopCompl_add (h : IsTopCompl p q) (φ₁ φ₂ : p →L[R] F) (ψ₁ ofIsTopCompl h (φ₁ + φ₂) (ψ₁ + ψ₂) = ofIsTopCompl h φ₁ ψ₁ + ofIsTopCompl h φ₂ ψ₂ := by ext; simp [ofIsTopCompl, add_add_add_comm] -@[simp] theorem range_ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : - LinearMap.range (ofIsTopCompl h φ ψ : E →ₗ[R] F) = φ.range ⊔ ψ.range := by - rw [coe_ofIsTopCompl] - exact LinearMap.range_ofIsCompl h.isCompl + LinearMap.range (ofIsTopCompl h φ ψ : E →ₗ[R] F) = φ.range ⊔ ψ.range := by simp end ContinuousLinearMap From 96fb29a578140ede77c3bd70713fc83d3411ce44 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 13 May 2026 09:27:34 -0400 Subject: [PATCH 064/210] fix --- Mathlib/Topology/Maps/Strict/Basic.lean | 2 -- 1 file changed, 2 deletions(-) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index 5ced836d06011c..83bae8f4523efb 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -153,6 +153,4 @@ lemma isEmbedding_iff_isStrictMap_injective : (Homeomorph.Quotient.congrRight <| by simp [f_inj.eq_iff]).trans Homeomorph.quotientBot exact f_strict.comp Φ.symm.isEmbedding -#check IsOpenQuotientMap - end Topology From d9332d48ba44c6048fefea15532aa37f0752575f Mon Sep 17 00:00:00 2001 From: sharky564 Date: Wed, 13 May 2026 23:34:58 +1000 Subject: [PATCH 065/210] Trigger CI From ec49839630e03741739c3bc96595f8a072ff2bbb Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 13 May 2026 09:41:04 -0400 Subject: [PATCH 066/210] . --- .../Normed/Operator/Perturbation/StrictByFinite.lean | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 9a1d431f040f88..08bf83549eb4ca 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -130,8 +130,8 @@ theorem step2_backward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : I theorem step2 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) : - (IsStrictMap u ∧ IsClosed (range u)) ↔ IsClosedEmbedding (restrict A u) := by - sorry + (IsStrictMap u ∧ IsClosed (range u)) ↔ IsClosedEmbedding (restrict A u) := + ⟨fun H ↦ step2_forward u A A_closed h_ker H.1 H.2, step2_backward u A A_closed h_ker⟩ /-! ### Step 3 @@ -139,8 +139,6 @@ theorem step2 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed ( We now deduce from the two previous step the full strength of the theorem. -/ -#check IsOpenQuotientMap - public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] : From e9e7038c1323c122775bac771dcfc30768beae4d Mon Sep 17 00:00:00 2001 From: sharky564 Date: Wed, 13 May 2026 23:44:37 +1000 Subject: [PATCH 067/210] Why is git doing this? --- Mathlib/Topology/Algebra/Module/Complement.lean | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 50571f7f610c4c..856fdf83751143 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -61,18 +61,6 @@ Because the condition is symmetric, a lot of lemmas could have a left and a righ In general we only include the left version, the right one being accessible through `Submodule.IsTopCompl.symm`. -## TODO - -There is still a significant part of the algebraic API which should be ported to the -topological setting. Notably, we should: -* show that `Submodule.prodEquivOfIsCompl` is a homeomorphism if and only if - the two subspaces are topological complements, and bundle it as a `ContinuousLinearEquiv` when - this is the case. (See the existing `ClosedComplemented.exists_submodule_equiv_prod`). -* show that `Submodule.quotientEquivOfIsCompl` is a homeomorphism if and only if - the two subspaces are topological complements, and bundle it as a `ContinuousLinearEquiv` when - this is the case. -* define `ContinuousLinearMap.ofIsTopCompl`, analogous to `LinearMap.ofIsCompl`. - -/ @[expose] public section From 30740ba512940294c3db8f0f26409af3297f8eb6 Mon Sep 17 00:00:00 2001 From: Sharvil Kesarwani Date: Thu, 14 May 2026 00:00:50 +1000 Subject: [PATCH 068/210] Update Mathlib/Topology/Algebra/Module/Complement.lean Co-authored-by: Anatole Dedecker --- Mathlib/Topology/Algebra/Module/Complement.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 856fdf83751143..6ecc2ac630eb95 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -29,7 +29,7 @@ change to something less misleading. to the definition given above. * `Submodule.ClosedComplemented`: we say that a submodule is (topologically) *complemented* if there exists a continuous projection `M →ₗ[R] p`. -* `Submodule.IsTopCompl.projectionOntoL`: if `h : IsTopCompl p q`, `p.projectionOntoL q h` is the +* `Submodule.projectionOntoL`: if `h : IsTopCompl p q`, `p.projectionOntoL q h` is the continuous linear projection `M →L[R] p` along `q`. This is the continuous version of `Submodule.projectionOnto`. * `Submodule.IsTopCompl.projectionL`: if `h : IsTopCompl p q`, `p.projectionL q h` is the continuous From ec534da9cc486bfbefce4e3b13de3e26648602e5 Mon Sep 17 00:00:00 2001 From: Sharvil Kesarwani Date: Thu, 14 May 2026 00:01:06 +1000 Subject: [PATCH 069/210] Update Mathlib/Topology/Algebra/Module/Complement.lean Co-authored-by: Anatole Dedecker --- Mathlib/Topology/Algebra/Module/Complement.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 6ecc2ac630eb95..d57b21796b9b71 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -32,7 +32,7 @@ change to something less misleading. * `Submodule.projectionOntoL`: if `h : IsTopCompl p q`, `p.projectionOntoL q h` is the continuous linear projection `M →L[R] p` along `q`. This is the continuous version of `Submodule.projectionOnto`. -* `Submodule.IsTopCompl.projectionL`: if `h : IsTopCompl p q`, `p.projectionL q h` is the continuous +* `Submodule.projectionL`: if `h : IsTopCompl p q`, `p.projectionL q h` is the continuous linear projection `M →L[R] M` onto `p` along `q`. This is the continuous version of `Submodule.IsCompl.projection`. * `Submodule.ClosedComplemented.complement`: an arbitrary topological complement of a topologically From 827ef734ab3fbee3057582ee2b81f8eba56dfdac Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 13 May 2026 11:09:08 -0400 Subject: [PATCH 070/210] Almost finish reduction --- .../Operator/Perturbation/StrictByFinite.lean | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 08bf83549eb4ca..2c5b8d45cbbc93 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -6,6 +6,7 @@ Authors: Anatole Dedecker module public import Mathlib.Topology.Maps.Strict.Basic +public import Mathlib.Topology.LocalAtTarget public import Mathlib.Topology.Algebra.Module.FiniteDimension /-! @@ -145,18 +146,34 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict (u : (IsStrictMap u ∧ IsClosed (range u)) ↔ (IsStrictMap (restrict A u) ∧ IsClosed (u '' A)) := by set N : Submodule 𝕜 E := A ⊓ u.ker + set π : E →L[𝕜] E ⧸ N := N.mkQL set v : E ⧸ N →L[𝕜] F := N.liftQL u inf_le_right - have v_eq_u : v ∘L N.mkQL = u := rfl + have π_quot : IsOpenQuotientMap π := N.isOpenQuotientMap_mkQL + have v_comp_π_eq_u : v ∘ π = u := rfl set B : Submodule 𝕜 (E ⧸ N) := map N.mkQ A - have comap_B : comap N.mkQ B = A := by simp [B, N] + have comap_B : comap π.toLinearMap B = A := by simp [B, N, π] + have A_mapsTo_B : MapsTo π A B := fun _ ↦ by simp [← comap_B] have B_closed : IsClosed (B : Set <| E ⧸ N) := by - rwa [← N.isQuotientMap_mkQ.isClosed_preimage, ← comap_coe, comap_B] + rwa [← π_quot.isQuotientMap.isClosed_preimage, ← π.coe_coe, ← comap_coe, comap_B] have codim_B : FiniteDimensional 𝕜 ((E ⧸ N) ⧸ B) := quotientQuotientEquivQuotient N A inf_le_left |>.symm.finiteDimensional + set π' : A →L[𝕜] B := + ⟨π.restrict A_mapsTo_B, π.continuous.restrict A_mapsTo_B⟩ + have π'_quot : IsOpenQuotientMap π' := by + let φ : (N.mkQL ⁻¹' B) ≃ₜ A := .setCongr congr(SetLike.coe $comap_B) + exact N.isOpenQuotientMap_mkQL.restrictPreimage B |>.comp + φ.symm.isOpenQuotientMap + have v_comp_π'_eq_u : restrict B v ∘ π' = restrict A u := rfl + have h_ker : Disjoint v.ker B := + sorry + have h_inj : Injective (restrict B v) := + sorry have range_eq : range v = range u := range_quot_lift _ - have image_eq : v '' B = u '' A := by simp [B, ← v_eq_u, ← image_comp] - rw [← range_eq, ← image_eq] - sorry + have image_eq : v '' B = u '' A := by simp [B, ← v_comp_π_eq_u, π, ← image_comp] + rw [← range_eq, ← image_eq, ← v_comp_π'_eq_u, ← v_comp_π_eq_u, + ← π_quot.isQuotientMap.isStrictMap_iff, ← π'_quot.isQuotientMap.isStrictMap_iff] + simp [step2 v B B_closed h_ker, isClosedEmbedding_iff, range_restrict v, + isEmbedding_iff_isStrictMap_injective, h_inj] end FiniteCodimSubspace From fbbc407dbc5a6eaaba14c1e836922499db0b42b4 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 13 May 2026 11:29:07 -0400 Subject: [PATCH 071/210] reduction done --- .../Operator/Perturbation/StrictByFinite.lean | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 2c5b8d45cbbc93..cc4082e09b4d57 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -164,16 +164,17 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict (u : exact N.isOpenQuotientMap_mkQL.restrictPreimage B |>.comp φ.symm.isOpenQuotientMap have v_comp_π'_eq_u : restrict B v ∘ π' = restrict A u := rfl - have h_ker : Disjoint v.ker B := - sorry - have h_inj : Injective (restrict B v) := - sorry + have v_ker : Disjoint v.ker B := by + simp [disjoint_iff, v, B, toLinearMap_liftQL, ker_liftQ, + map_inf_eq_map_inf_comap, comap_map_mkQ, N, inf_comm] + have v_restr_inj : Injective (restrict B v) := + injOn_iff_injective.mp <| LinearMap.injOn_of_disjoint_ker subset_rfl v_ker.symm have range_eq : range v = range u := range_quot_lift _ have image_eq : v '' B = u '' A := by simp [B, ← v_comp_π_eq_u, π, ← image_comp] rw [← range_eq, ← image_eq, ← v_comp_π'_eq_u, ← v_comp_π_eq_u, ← π_quot.isQuotientMap.isStrictMap_iff, ← π'_quot.isQuotientMap.isStrictMap_iff] - simp [step2 v B B_closed h_ker, isClosedEmbedding_iff, range_restrict v, - isEmbedding_iff_isStrictMap_injective, h_inj] + simp [step2 v B B_closed v_ker, isClosedEmbedding_iff, range_restrict v, + isEmbedding_iff_isStrictMap_injective, v_restr_inj] end FiniteCodimSubspace From 270d715d9c65b1aecd717193b0fff5527110fbfb Mon Sep 17 00:00:00 2001 From: sharky564 Date: Thu, 14 May 2026 02:16:29 +1000 Subject: [PATCH 072/210] Incorporated PR feedback --- .../Topology/Algebra/Module/Complement.lean | 68 ++++++++++--------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 856fdf83751143..8f3dae15e16c86 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -37,9 +37,9 @@ change to something less misleading. `Submodule.IsCompl.projection`. * `Submodule.ClosedComplemented.complement`: an arbitrary topological complement of a topologically complemented submodule. -* `Submodule.IsTopCompl.prodEquiv`: the bundled continuous linear equivalence `p × q ≃L[R] M` +* `Submodule.prodEquivOfIsTopCompl`: the bundled continuous linear equivalence `p × q ≃L[R] M` arising from a topological complement pair. -* `Submodule.IsTopCompl.quotientEquiv`: the bundled continuous linear equivalence `M ⧸ p ≃L[R] q` +* `Submodule.quotientEquivOfIsTopCompl`: the bundled continuous linear equivalence `M ⧸ p ≃L[R] q` arising from a topological complement pair. * `ContinuousLinearMap.ofIsTopCompl`: the continuous linear map induced by maps on a topological complement pair. @@ -399,7 +399,7 @@ variable [IsTopologicalAddGroup M] /-- Two submodules `p` and `q` are topological complements if and only if the algebraic equivalence `p.prodEquivOfIsCompl q h` is continuous in the inverse direction. -/ -theorem _root_.IsCompl.isTopCompl_iff_continuous_prodEquiv_symm (h : IsCompl p q) : +theorem isTopCompl_iff_continuous_prodEquiv_symm (h : IsCompl p q) : IsTopCompl p q ↔ Continuous (p.prodEquivOfIsCompl q h).symm := ⟨fun hTop ↦ ((p.projectionOntoL q hTop).prod (q.projectionOntoL p hTop.symm)).continuous.congr fun x ↦ (prodEquivOfIsCompl_symm_apply h x).symm, @@ -407,85 +407,90 @@ theorem _root_.IsCompl.isTopCompl_iff_continuous_prodEquiv_symm (h : IsCompl p q /-- The algebraic equivalence `p.prodEquivOfIsCompl q h : p × q ≃ₗ[R] M` from a pair of complementary submodules is always continuous as a map `p × q → M`. -/ -theorem continuous_prodEquivOfIsCompl (h : IsCompl p q) : - Continuous (p.prodEquivOfIsCompl q h) := +theorem continuous_prodEquivOfIsCompl (h : IsCompl p q) : Continuous (p.prodEquivOfIsCompl q h) := (continuous_subtype_val.comp continuous_fst).add (continuous_subtype_val.comp continuous_snd) /-- Two submodules `p` and `q` are topological complements if and only if the algebraic equivalence `p.prodEquivOfIsCompl q h` is a homeomorphism. -/ -theorem _root_.IsCompl.isTopCompl_iff_isHomeomorph_prodEquiv (h : IsCompl p q) : +theorem isTopCompl_iff_isHomeomorph_prodEquiv (h : IsCompl p q) : IsTopCompl p q ↔ IsHomeomorph (p.prodEquivOfIsCompl q h) := by - rw [(p.prodEquivOfIsCompl q h).isHomeomorph_iff, h.isTopCompl_iff_continuous_prodEquiv_symm, + rw [(p.prodEquivOfIsCompl q h).isHomeomorph_iff, isTopCompl_iff_continuous_prodEquiv_symm, and_iff_right] exact continuous_prodEquivOfIsCompl h +variable (p q) in /-- If two submodules `p` and `q` are topological complements, then the algebraic equivalence `p.prodEquivOfIsCompl q h.isCompl` is a homeomorphism, bundled as a continuous linear equivalence. -/ -noncomputable def IsTopCompl.prodEquiv (h : IsTopCompl p q) : (p × q) ≃L[R] M := +noncomputable def prodEquivOfIsTopCompl (h : IsTopCompl p q) : (p × q) ≃L[R] M := { p.prodEquivOfIsCompl q h.isCompl with continuous_toFun := continuous_prodEquivOfIsCompl h.isCompl - continuous_invFun := h.isCompl.isTopCompl_iff_continuous_prodEquiv_symm.mp h } + continuous_invFun := (isTopCompl_iff_continuous_prodEquiv_symm h.isCompl).mp h } @[simp] -theorem IsTopCompl.coe_prodEquiv (h : IsTopCompl p q) : - (h.prodEquiv : (p × q) →ₗ[R] M) = p.prodEquivOfIsCompl q h.isCompl := +theorem coe_prodEquivOfIsTopCompl (h : IsTopCompl p q) : + (prodEquivOfIsTopCompl p q h : (p × q) →ₗ[R] M) = p.prodEquivOfIsCompl q h.isCompl := rfl @[simp] -theorem IsTopCompl.coe_prodEquiv_symm (h : IsTopCompl p q) : - (h.prodEquiv.symm : M →ₗ[R] p × q) = (p.prodEquivOfIsCompl q h.isCompl).symm := +theorem coe_prodEquivOfIsTopCompl_symm (h : IsTopCompl p q) : + ((prodEquivOfIsTopCompl p q h).symm : M →ₗ[R] p × q) = + (p.prodEquivOfIsCompl q h.isCompl).symm := rfl @[simp] -theorem IsTopCompl.prodEquiv_apply (h : IsTopCompl p q) (x : p × q) : - h.prodEquiv x = (x.1 : M) + x.2 := +theorem prodEquivOfIsTopCompl_apply (h : IsTopCompl p q) (x : p × q) : + prodEquivOfIsTopCompl p q h x = (x.1 : M) + x.2 := rfl @[simp] -theorem IsTopCompl.prodEquiv_symm_apply (h : IsTopCompl p q) (x : M) : - h.prodEquiv.symm x = ((p.projectionOntoL q h x, q.projectionOntoL p h.symm x) : p × q) := +theorem prodEquivOfIsTopCompl_symm_apply (h : IsTopCompl p q) (x : M) : + (prodEquivOfIsTopCompl p q h).symm x = + ((p.projectionOntoL q h x, q.projectionOntoL p h.symm x) : p × q) := prodEquivOfIsCompl_symm_apply h.isCompl x /-- Two submodules `p` and `q` are topological complements if and only if the algebraic equivalence `p.quotientEquivOfIsCompl q h` is continuous. -/ -theorem IsCompl.isTopCompl_iff_continuous_quotientEquiv (h : IsCompl p q) : +theorem isTopCompl_iff_continuous_quotientEquiv (h : IsCompl p q) : IsTopCompl p q ↔ Continuous (p.quotientEquivOfIsCompl q h) := by have hproj : ⇑(p.quotientEquivOfIsCompl q h) ∘ ⇑p.mkQ = ⇑(q.projectionOnto p h.symm) := by funext; simp rw [p.isQuotientMap_mkQL.continuous_iff, coe_mkQL, hproj, ← h.symm.isTopCompl_iff_projectionOnto] exact ⟨IsTopCompl.symm, IsTopCompl.symm⟩ +variable (p q) in /-- If two submodules `p` and `q` are topological complements, then the algebraic equivalence `p.quotientEquivOfIsCompl q h.isCompl` is a homeomorphism, bundled as a continuous linear equivalence. -/ -noncomputable def IsTopCompl.quotientEquiv (h : IsTopCompl p q) : (M ⧸ p) ≃L[R] q := +noncomputable def quotientEquivOfIsTopCompl (h : IsTopCompl p q) : (M ⧸ p) ≃L[R] q := { p.quotientEquivOfIsCompl q h.isCompl with - continuous_toFun := (h.isCompl.isTopCompl_iff_continuous_quotientEquiv).mp h + continuous_toFun := (isTopCompl_iff_continuous_quotientEquiv h.isCompl).mp h continuous_invFun := (p.mkQL.comp q.subtypeL).continuous } @[simp] -theorem IsTopCompl.coe_quotientEquiv (h : IsTopCompl p q) : - (h.quotientEquiv : (M ⧸ p) →ₗ[R] q) = p.quotientEquivOfIsCompl q h.isCompl := +theorem coe_quotientEquivOfIsTopCompl (h : IsTopCompl p q) : + (quotientEquivOfIsTopCompl p q h : (M ⧸ p) →ₗ[R] q) = p.quotientEquivOfIsCompl q h.isCompl := rfl @[simp] -theorem IsTopCompl.coe_quotientEquiv_symm (h : IsTopCompl p q) : - (h.quotientEquiv.symm : q →ₗ[R] M ⧸ p) = (p.quotientEquivOfIsCompl q h.isCompl).symm := +theorem coe_quotientEquivOfIsTopCompl_symm (h : IsTopCompl p q) : + ((quotientEquivOfIsTopCompl p q h).symm : q →ₗ[R] M ⧸ p) = + (p.quotientEquivOfIsCompl q h.isCompl).symm := rfl -theorem IsTopCompl.quotientEquiv_apply (h : IsTopCompl p q) (x : M ⧸ p) : - h.quotientEquiv x = p.quotientEquivOfIsCompl q h.isCompl x := +theorem quotientEquivOfIsTopCompl_apply (h : IsTopCompl p q) (x : M ⧸ p) : + quotientEquivOfIsTopCompl p q h x = p.quotientEquivOfIsCompl q h.isCompl x := rfl @[simp] -theorem IsTopCompl.quotientEquiv_symm_apply (h : IsTopCompl p q) (y : q) : - h.quotientEquiv.symm y = p.mkQ y := +theorem quotientEquivOfIsTopCompl_symm_apply (h : IsTopCompl p q) (y : q) : + (quotientEquivOfIsTopCompl p q h).symm y = p.mkQ y := rfl @[simp] -theorem IsTopCompl.quotientEquiv_apply_mk (h : IsTopCompl p q) (x : M) : - h.quotientEquiv (Submodule.Quotient.mk x) = q.projectionOnto p h.isCompl.symm x := +theorem quotientEquivOfIsTopCompl_apply_mk (h : IsTopCompl p q) (x : M) : + quotientEquivOfIsTopCompl p q h (Submodule.Quotient.mk x) = + q.projectionOnto p h.isCompl.symm x := quotientEquivOfIsCompl_apply_mk h.isCompl x end ContinuousLinearEquiv @@ -527,8 +532,7 @@ theorem ofIsTopCompl_eq (h : IsTopCompl p q) {φ : p →L[R] F} {ψ : q →L[R] simp [hφ, hψ] @[simp] -theorem ofIsTopCompl_zero (h : IsTopCompl p q) : - (ofIsTopCompl h 0 0 : E →L[R] F) = 0 := by +theorem ofIsTopCompl_zero (h : IsTopCompl p q) : (ofIsTopCompl h 0 0 : E →L[R] F) = 0 := by ext; simp [ofIsTopCompl] @[simp] From 78415555ecfc91318ad984ae2f0921157a1dfe17 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 13 May 2026 16:59:06 -0400 Subject: [PATCH 073/210] Two sorries left! --- .../Operator/Perturbation/StrictByFinite.lean | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index cc4082e09b4d57..6be23264a016f1 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -70,7 +70,7 @@ theorem step1_foward (A : Submodule 𝕜 E) (K : Submodule 𝕜 E) (A_closed : I Note the hypothesis `h_ker` is implied `h_clemb`, but since this is a private theorem we just write the most convenient statement to prove and use. -/ -theorem step1_backward (A : Submodule 𝕜 E) (u : E →L[𝕜] F) (A_closed : IsClosed (A : Set E)) +theorem step1_backward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) (h_clemb : IsClosedEmbedding (restrict A u)) : IsQuotientMap u := by @@ -107,7 +107,9 @@ theorem step2_forward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : Is let u' : E ⧸ u.ker →L[𝕜] F := u.ker.liftQL u le_rfl have u'_clemb : IsClosedEmbedding u' := by constructor - · sorry -- should be fixed with more API on strict homs + · have : Injective u' := by simp [u', ← LinearMap.ker_eq_bot, ker_liftQ_eq_bot] + simpa [isEmbedding_iff_isStrictMap_injective, this, and_true, + u.ker.isQuotientMap_mkQL.isStrictMap_iff] · simpa [u', ← LinearMap.coe_range, Submodule.range_liftQ] let π : E →L[𝕜] E ⧸ u.ker := u.ker.mkQL have π_restr_clemb : IsClosedEmbedding (restrict A π) := @@ -122,12 +124,17 @@ theorem step2_backward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : I rcases A.exists_isCompl with ⟨S, A_compl_S⟩ have : FiniteDimensional 𝕜 S := quotientEquivOfIsCompl A S A_compl_S |>.finiteDimensional - rw [isClosedEmbedding_iff, range_restrict] at h_clemb - have : range u = (map u.toLinearMap A ⊔ map u.toLinearMap S) := by - rw [← Submodule.map_sup, A_compl_S.sup_eq_top, Submodule.map_top, - LinearMap.coe_range, ContinuousLinearMap.coe_coe] - refine ⟨?_, this ▸ Submodule.isClosed_sup_finiteDimensional _ _ h_clemb.2⟩ - sorry + have range_u_closed : IsClosed (u.range : Set F) := by + rw [isClosedEmbedding_iff, range_restrict] at h_clemb + have : u.range = (map u.toLinearMap A ⊔ map u.toLinearMap S) := by + rw [← Submodule.map_sup, A_compl_S.sup_eq_top, Submodule.map_top] + exact this ▸ Submodule.isClosed_sup_finiteDimensional _ _ h_clemb.2 + refine ⟨?_, range_u_closed⟩ + set u' : E →L[𝕜] u.range := u.rangeRestrict + have h_clemb' : IsClosedEmbedding (restrict A u') := by + rw [← range_u_closed.isClosedEmbedding_subtypeVal.of_comp_iff] + exact h_clemb + exact step1_backward u' A A_closed (by simpa [u']) (by simp [u']) h_clemb' theorem step2 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) : From 5d29bac7b28334e8c9c93ccdc992295ed760856a Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 13 May 2026 18:35:41 -0400 Subject: [PATCH 074/210] feat: semilinearize LinearMap.restrict --- .../Algebra/Module/Submodule/LinearMap.lean | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/Mathlib/Algebra/Module/Submodule/LinearMap.lean b/Mathlib/Algebra/Module/Submodule/LinearMap.lean index aeedfbc5aad8a9..aeab9007abecef 100644 --- a/Mathlib/Algebra/Module/Submodule/LinearMap.lean +++ b/Mathlib/Algebra/Module/Submodule/LinearMap.lean @@ -206,33 +206,31 @@ theorem comp_codLift : end /-- Restrict domain and codomain of a linear map. -/ -def restrict (f : M →ₗ[R] M₁) {p : Submodule R M} {q : Submodule R M₁} (hf : ∀ x ∈ p, f x ∈ q) : - p →ₗ[R] q := +def restrict (f : M →ₛₗ[σ₁₂] M₂) {p : Submodule R M} {q : Submodule R₂ M₂} (hf : ∀ x ∈ p, f x ∈ q) : + p →ₛₗ[σ₁₂] q := (f.domRestrict p).codRestrict q <| SetLike.forall.2 hf @[simp] -theorem restrict_coe_apply (f : M →ₗ[R] M₁) {p : Submodule R M} {q : Submodule R M₁} +theorem restrict_coe_apply (f : M →ₛₗ[σ₁₂] M₂) {p : Submodule R M} {q : Submodule R₂ M₂} (hf : ∀ x ∈ p, f x ∈ q) (x : p) : ↑(f.restrict hf x) = f x := rfl -theorem restrict_apply {f : M →ₗ[R] M₁} {p : Submodule R M} {q : Submodule R M₁} +theorem restrict_apply {f : M →ₛₗ[σ₁₂] M₂} {p : Submodule R M} {q : Submodule R₂ M₂} (hf : ∀ x ∈ p, f x ∈ q) (x : p) : f.restrict hf x = ⟨f x, hf x.1 x.2⟩ := rfl -lemma restrict_sub {R M M₁ : Type*} - [Ring R] [AddCommGroup M] [AddCommGroup M₁] [Module R M] [Module R M₁] - {p : Submodule R M} {q : Submodule R M₁} {f g : M →ₗ[R] M₁} +lemma restrict_sub {R R₂ M M₂ : Type*} + [Ring R] [Ring R₂] {σ₁₂ : R →+* R₂} [AddCommGroup M] [AddCommGroup M₂] + [Module R M] [Module R₂ M₂] {p : Submodule R M} {q : Submodule R₂ M₂} {f g : M →ₛₗ[σ₁₂] M₂} (hf : MapsTo f p q) (hg : MapsTo g p q) (hfg : MapsTo (f - g) p q := fun _ hx ↦ q.sub_mem (hf hx) (hg hx)) : f.restrict hf - g.restrict hg = (f - g).restrict hfg := by ext; simp -lemma restrict_comp - {M₂ M₃ : Type*} [AddCommMonoid M₂] [AddCommMonoid M₃] [Module R M₂] [Module R M₃] - {p : Submodule R M} {p₂ : Submodule R M₂} {p₃ : Submodule R M₃} - {f : M →ₗ[R] M₂} {g : M₂ →ₗ[R] M₃} - (hf : MapsTo f p p₂) (hg : MapsTo g p₂ p₃) (hfg : MapsTo (g ∘ₗ f) p p₃ := hg.comp hf) : - (g ∘ₗ f).restrict hfg = (g.restrict hg) ∘ₗ (f.restrict hf) := +lemma restrict_comp {p : Submodule R M} {p₂ : Submodule R₂ M₂} {p₃ : Submodule R₃ M₃} + {f : M →ₛₗ[σ₁₂] M₂} {g : M₂ →ₛₗ[σ₂₃] M₃} + (hf : MapsTo f p p₂) (hg : MapsTo g p₂ p₃) (hfg : MapsTo (g ∘ₛₗ f) p p₃ := hg.comp hf) : + (g ∘ₛₗ f).restrict hfg = (g.restrict hg) ∘ₛₗ (f.restrict hf) := rfl -- TODO Consider defining `Algebra R (p.compatibleMaps p)`, `AlgHom` version of `LinearMap.restrict` @@ -248,17 +246,17 @@ lemma restrict_commute {f g : M →ₗ[R] M} (h : Commute f g) {p : Submodule R change (f ∘ₗ g).restrict (hf.comp hg) = (g ∘ₗ f).restrict (hg.comp hf) congr 1 -theorem subtype_comp_restrict {f : M →ₗ[R] M₁} {p : Submodule R M} {q : Submodule R M₁} +theorem subtype_comp_restrict {f : M →ₛₗ[σ₁₂] M₂} {p : Submodule R M} {q : Submodule R₂ M₂} (hf : ∀ x ∈ p, f x ∈ q) : q.subtype.comp (f.restrict hf) = f.domRestrict p := rfl -theorem restrict_eq_codRestrict_domRestrict {f : M →ₗ[R] M₁} {p : Submodule R M} - {q : Submodule R M₁} (hf : ∀ x ∈ p, f x ∈ q) : +theorem restrict_eq_codRestrict_domRestrict {f : M →ₛₗ[σ₁₂] M₂} {p : Submodule R M} + {q : Submodule R₂ M₂} (hf : ∀ x ∈ p, f x ∈ q) : f.restrict hf = (f.domRestrict p).codRestrict q fun x => hf x.1 x.2 := rfl -theorem restrict_eq_domRestrict_codRestrict {f : M →ₗ[R] M₁} {p : Submodule R M} - {q : Submodule R M₁} (hf : ∀ x, f x ∈ q) : +theorem restrict_eq_domRestrict_codRestrict {f : M →ₛₗ[σ₁₂] M₂} {p : Submodule R M} + {q : Submodule R₂ M₂} (hf : ∀ x, f x ∈ q) : (f.restrict fun x _ => hf x) = (f.codRestrict q hf).domRestrict p := rfl From f4294383749b762f1e0394bfe7bed9e0f8a4fa5b Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 13 May 2026 18:54:37 -0400 Subject: [PATCH 075/210] feat: ContinuousLinearMap.restrict --- .../Algebra/Module/Submodule/LinearMap.lean | 7 ++++- .../Topology/Algebra/Module/LinearMap.lean | 29 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Mathlib/Algebra/Module/Submodule/LinearMap.lean b/Mathlib/Algebra/Module/Submodule/LinearMap.lean index aeab9007abecef..ac0ec6cac5caa0 100644 --- a/Mathlib/Algebra/Module/Submodule/LinearMap.lean +++ b/Mathlib/Algebra/Module/Submodule/LinearMap.lean @@ -211,6 +211,11 @@ def restrict (f : M →ₛₗ[σ₁₂] M₂) {p : Submodule R M} {q : Submodule (f.domRestrict p).codRestrict q <| SetLike.forall.2 hf @[simp] +theorem coe_restrict_apply {f : M →ₛₗ[σ₁₂] M₂} {p : Submodule R M} {q : Submodule R₂ M₂} + (hf : ∀ x ∈ p, f x ∈ q) (x : p) : ↑(f.restrict hf x) = f x := + rfl + +@[deprecated coe_restrict_apply (since := "2026-05-13")] theorem restrict_coe_apply (f : M →ₛₗ[σ₁₂] M₂) {p : Submodule R M} {q : Submodule R₂ M₂} (hf : ∀ x ∈ p, f x ∈ q) (x : p) : ↑(f.restrict hf x) = f x := rfl @@ -299,7 +304,7 @@ theorem _root_.Module.End.pow_restrict {p : Submodule R M} (n : ℕ) (h : ∀ x (h' := Module.End.pow_apply_mem_of_forall_mem n h) : (f'.restrict h) ^ n = (f' ^ n).restrict h' := by ext x - have : Semiconj (↑) (f'.restrict h) f' := fun _ ↦ restrict_coe_apply _ _ _ + have : Semiconj (↑) (f'.restrict h) f' := fun _ ↦ coe_restrict_apply _ _ simp [Module.End.coe_pow, this.iterate_right _ _] end diff --git a/Mathlib/Topology/Algebra/Module/LinearMap.lean b/Mathlib/Topology/Algebra/Module/LinearMap.lean index a749f8756c9b21..1c37f32cec271c 100644 --- a/Mathlib/Topology/Algebra/Module/LinearMap.lean +++ b/Mathlib/Topology/Algebra/Module/LinearMap.lean @@ -702,6 +702,35 @@ theorem coe_rangeRestrict [RingHomSurjective σ₁₂] (f : M₁ →SL[σ₁₂] (f : M₁ →ₛₗ[σ₁₂] M₂).rangeRestrict := rfl +/-- Restrict codomain of a continuous linear map. -/ +def restrict (f : M₁ →SL[σ₁₂] M₂) {p : Submodule R₁ M₁} {q : Submodule R₂ M₂} + (h : ∀ x ∈ p, f x ∈ q) : + p →SL[σ₁₂] q where + toLinearMap := f.toLinearMap.restrict h + cont := f.continuous.restrict h + +@[simp, norm_cast] +theorem toLinearMap_restrict {f : M₁ →SL[σ₁₂] M₂} {p : Submodule R₁ M₁} {q : Submodule R₂ M₂} + (h : ∀ x ∈ p, f x ∈ q) : + (f.restrict h).toLinearMap = f.toLinearMap.restrict h := + rfl + +@[simp] +theorem coe_restrict_apply {f : M₁ →SL[σ₁₂] M₂} {p : Submodule R₁ M₁} {q : Submodule R₂ M₂} + (hf : ∀ x ∈ p, f x ∈ q) (x : p) : ↑(f.restrict hf x) = f x := + rfl + +theorem restrict_apply {f : M₁ →SL[σ₁₂] M₂} {p : Submodule R₁ M₁} {q : Submodule R₂ M₂} + (hf : ∀ x ∈ p, f x ∈ q) (x : p) : f.restrict hf x = ⟨f x, hf x.1 x.2⟩ := + rfl + +open Set in +lemma restrict_comp {p : Submodule R₁ M₁} {p₂ : Submodule R₂ M₂} {p₃ : Submodule R₃ M₃} + {f : M₁ →SL[σ₁₂] M₂} {g : M₂ →SL[σ₂₃] M₃} + (hf : MapsTo f p p₂) (hg : MapsTo g p₂ p₃) (hfg : MapsTo (g.comp f) p p₃ := hg.comp hf) : + (g.comp f).restrict hfg = (g.restrict hg).comp (f.restrict hf) := + rfl + section variable {R S : Type*} [Semiring R] [Semiring S] [Module R M₁] [Module R M₂] [Module R S] From b1f5177957fc294553676a6695d25f8f2720ae32 Mon Sep 17 00:00:00 2001 From: sharky564 Date: Thu, 14 May 2026 08:58:31 +1000 Subject: [PATCH 076/210] Added IsCompl namespace --- Mathlib/Topology/Algebra/Module/Complement.lean | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index a4fe6eccc0b34f..2de186c23ad9d1 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -399,7 +399,7 @@ variable [IsTopologicalAddGroup M] /-- Two submodules `p` and `q` are topological complements if and only if the algebraic equivalence `p.prodEquivOfIsCompl q h` is continuous in the inverse direction. -/ -theorem isTopCompl_iff_continuous_prodEquiv_symm (h : IsCompl p q) : +theorem IsCompl.isTopCompl_iff_continuous_prodEquiv_symm (h : IsCompl p q) : IsTopCompl p q ↔ Continuous (p.prodEquivOfIsCompl q h).symm := ⟨fun hTop ↦ ((p.projectionOntoL q hTop).prod (q.projectionOntoL p hTop.symm)).continuous.congr fun x ↦ (prodEquivOfIsCompl_symm_apply h x).symm, @@ -412,7 +412,7 @@ theorem continuous_prodEquivOfIsCompl (h : IsCompl p q) : Continuous (p.prodEqui /-- Two submodules `p` and `q` are topological complements if and only if the algebraic equivalence `p.prodEquivOfIsCompl q h` is a homeomorphism. -/ -theorem isTopCompl_iff_isHomeomorph_prodEquiv (h : IsCompl p q) : +theorem IsCompl.isTopCompl_iff_isHomeomorph_prodEquiv (h : IsCompl p q) : IsTopCompl p q ↔ IsHomeomorph (p.prodEquivOfIsCompl q h) := by rw [(p.prodEquivOfIsCompl q h).isHomeomorph_iff, isTopCompl_iff_continuous_prodEquiv_symm, and_iff_right] @@ -425,7 +425,7 @@ variable (p q) in noncomputable def prodEquivOfIsTopCompl (h : IsTopCompl p q) : (p × q) ≃L[R] M := { p.prodEquivOfIsCompl q h.isCompl with continuous_toFun := continuous_prodEquivOfIsCompl h.isCompl - continuous_invFun := (isTopCompl_iff_continuous_prodEquiv_symm h.isCompl).mp h } + continuous_invFun := h.isCompl.isTopCompl_iff_continuous_prodEquiv_symm.mp h } @[simp] theorem coe_prodEquivOfIsTopCompl (h : IsTopCompl p q) : @@ -451,7 +451,7 @@ theorem prodEquivOfIsTopCompl_symm_apply (h : IsTopCompl p q) (x : M) : /-- Two submodules `p` and `q` are topological complements if and only if the algebraic equivalence `p.quotientEquivOfIsCompl q h` is continuous. -/ -theorem isTopCompl_iff_continuous_quotientEquiv (h : IsCompl p q) : +theorem IsCompl.isTopCompl_iff_continuous_quotientEquiv (h : IsCompl p q) : IsTopCompl p q ↔ Continuous (p.quotientEquivOfIsCompl q h) := by have hproj : ⇑(p.quotientEquivOfIsCompl q h) ∘ ⇑p.mkQ = ⇑(q.projectionOnto p h.symm) := by funext; simp @@ -464,7 +464,7 @@ variable (p q) in equivalence. -/ noncomputable def quotientEquivOfIsTopCompl (h : IsTopCompl p q) : (M ⧸ p) ≃L[R] q := { p.quotientEquivOfIsCompl q h.isCompl with - continuous_toFun := (isTopCompl_iff_continuous_quotientEquiv h.isCompl).mp h + continuous_toFun := h.isCompl.isTopCompl_iff_continuous_quotientEquiv.mp h continuous_invFun := (p.mkQL.comp q.subtypeL).continuous } @[simp] From b6cab2990befeaa68c0ba59ddab7524a0ffc4f4c Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 13 May 2026 18:59:55 -0400 Subject: [PATCH 077/210] does not typecheck --- .../Topology/Algebra/Module/LinearMap.lean | 128 ++++++++++-------- 1 file changed, 68 insertions(+), 60 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/LinearMap.lean b/Mathlib/Topology/Algebra/Module/LinearMap.lean index 1c37f32cec271c..0ec1ceb3faf5d2 100644 --- a/Mathlib/Topology/Algebra/Module/LinearMap.lean +++ b/Mathlib/Topology/Algebra/Module/LinearMap.lean @@ -671,66 +671,6 @@ instance completeSpace_eqLocus {M' : Type*} [UniformSpace M'] [CompleteSpace M'] (f g : M' →SL[σ₁₂] M₂) : CompleteSpace (LinearMap.eqLocus f g) := IsClosed.completeSpace_coe (hs := isClosed_eq (map_continuous f) (map_continuous g)) -/-- Restrict codomain of a continuous linear map. -/ -def codRestrict (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₂ M₂) (h : ∀ x, f x ∈ p) : - M₁ →SL[σ₁₂] p where - cont := f.continuous.subtype_mk _ - toLinearMap := (f : M₁ →ₛₗ[σ₁₂] M₂).codRestrict p h - -@[norm_cast] -theorem coe_codRestrict (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₂ M₂) (h : ∀ x, f x ∈ p) : - (f.codRestrict p h : M₁ →ₛₗ[σ₁₂] p) = (f : M₁ →ₛₗ[σ₁₂] M₂).codRestrict p h := - rfl - -@[simp] -theorem coe_codRestrict_apply (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₂ M₂) (h : ∀ x, f x ∈ p) (x) : - (f.codRestrict p h x : M₂) = f x := - rfl - -@[simp] -theorem ker_codRestrict (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₂ M₂) (h : ∀ x, f x ∈ p) : - ker (f.codRestrict p h : M₁ →ₛₗ[σ₁₂] p) = ker (f : M₁ →ₛₗ[σ₁₂] M₂) := - (f : M₁ →ₛₗ[σ₁₂] M₂).ker_codRestrict p h - -/-- Restrict the codomain of a continuous linear map `f` to `f.range`. -/ -abbrev rangeRestrict [RingHomSurjective σ₁₂] (f : M₁ →SL[σ₁₂] M₂) := - f.codRestrict (LinearMap.range (f : M₁ →ₛₗ[σ₁₂] M₂)) (LinearMap.mem_range_self _) - -@[simp] -theorem coe_rangeRestrict [RingHomSurjective σ₁₂] (f : M₁ →SL[σ₁₂] M₂) : - (f.rangeRestrict : M₁ →ₛₗ[σ₁₂] LinearMap.range (f : M₁ →ₛₗ[σ₁₂] M₂)) = - (f : M₁ →ₛₗ[σ₁₂] M₂).rangeRestrict := - rfl - -/-- Restrict codomain of a continuous linear map. -/ -def restrict (f : M₁ →SL[σ₁₂] M₂) {p : Submodule R₁ M₁} {q : Submodule R₂ M₂} - (h : ∀ x ∈ p, f x ∈ q) : - p →SL[σ₁₂] q where - toLinearMap := f.toLinearMap.restrict h - cont := f.continuous.restrict h - -@[simp, norm_cast] -theorem toLinearMap_restrict {f : M₁ →SL[σ₁₂] M₂} {p : Submodule R₁ M₁} {q : Submodule R₂ M₂} - (h : ∀ x ∈ p, f x ∈ q) : - (f.restrict h).toLinearMap = f.toLinearMap.restrict h := - rfl - -@[simp] -theorem coe_restrict_apply {f : M₁ →SL[σ₁₂] M₂} {p : Submodule R₁ M₁} {q : Submodule R₂ M₂} - (hf : ∀ x ∈ p, f x ∈ q) (x : p) : ↑(f.restrict hf x) = f x := - rfl - -theorem restrict_apply {f : M₁ →SL[σ₁₂] M₂} {p : Submodule R₁ M₁} {q : Submodule R₂ M₂} - (hf : ∀ x ∈ p, f x ∈ q) (x : p) : f.restrict hf x = ⟨f x, hf x.1 x.2⟩ := - rfl - -open Set in -lemma restrict_comp {p : Submodule R₁ M₁} {p₂ : Submodule R₂ M₂} {p₃ : Submodule R₃ M₃} - {f : M₁ →SL[σ₁₂] M₂} {g : M₂ →SL[σ₂₃] M₃} - (hf : MapsTo f p p₂) (hg : MapsTo g p₂ p₃) (hfg : MapsTo (g.comp f) p p₃ := hg.comp hf) : - (g.comp f).restrict hfg = (g.restrict hg).comp (f.restrict hf) := - rfl - section variable {R S : Type*} [Semiring R] [Semiring S] [Module R M₁] [Module R M₂] [Module R S] @@ -1340,6 +1280,74 @@ end Ring end Submodule +section Restrict + +namespace ContinuousLinearMap + +/-- Restrict codomain of a continuous linear map. -/ +def codRestrict (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₂ M₂) (h : ∀ x, f x ∈ p) : + M₁ →SL[σ₁₂] p where + cont := f.continuous.subtype_mk _ + toLinearMap := (f : M₁ →ₛₗ[σ₁₂] M₂).codRestrict p h + +@[norm_cast] +theorem coe_codRestrict (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₂ M₂) (h : ∀ x, f x ∈ p) : + (f.codRestrict p h : M₁ →ₛₗ[σ₁₂] p) = (f : M₁ →ₛₗ[σ₁₂] M₂).codRestrict p h := + rfl + +@[simp] +theorem coe_codRestrict_apply (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₂ M₂) (h : ∀ x, f x ∈ p) (x) : + (f.codRestrict p h x : M₂) = f x := + rfl + +@[simp] +theorem ker_codRestrict (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₂ M₂) (h : ∀ x, f x ∈ p) : + ker (f.codRestrict p h : M₁ →ₛₗ[σ₁₂] p) = ker (f : M₁ →ₛₗ[σ₁₂] M₂) := + (f : M₁ →ₛₗ[σ₁₂] M₂).ker_codRestrict p h + +/-- Restrict the codomain of a continuous linear map `f` to `f.range`. -/ +abbrev rangeRestrict [RingHomSurjective σ₁₂] (f : M₁ →SL[σ₁₂] M₂) := + f.codRestrict (LinearMap.range (f : M₁ →ₛₗ[σ₁₂] M₂)) (LinearMap.mem_range_self _) + +@[simp] +theorem coe_rangeRestrict [RingHomSurjective σ₁₂] (f : M₁ →SL[σ₁₂] M₂) : + (f.rangeRestrict : M₁ →ₛₗ[σ₁₂] LinearMap.range (f : M₁ →ₛₗ[σ₁₂] M₂)) = + (f : M₁ →ₛₗ[σ₁₂] M₂).rangeRestrict := + rfl + +/-- Restrict codomain of a continuous linear map. -/ +def restrict (f : M₁ →SL[σ₁₂] M₂) {p : Submodule R₁ M₁} {q : Submodule R₂ M₂} + (h : ∀ x ∈ p, f x ∈ q) : + p →SL[σ₁₂] q where + toLinearMap := f.toLinearMap.restrict h + cont := f.continuous.restrict h + +@[simp, norm_cast] +theorem toLinearMap_restrict {f : M₁ →SL[σ₁₂] M₂} {p : Submodule R₁ M₁} {q : Submodule R₂ M₂} + (h : ∀ x ∈ p, f x ∈ q) : + (f.restrict h).toLinearMap = f.toLinearMap.restrict h := + rfl + +@[simp] +theorem coe_restrict_apply {f : M₁ →SL[σ₁₂] M₂} {p : Submodule R₁ M₁} {q : Submodule R₂ M₂} + (hf : ∀ x ∈ p, f x ∈ q) (x : p) : ↑(f.restrict hf x) = f x := + rfl + +theorem restrict_apply {f : M₁ →SL[σ₁₂] M₂} {p : Submodule R₁ M₁} {q : Submodule R₂ M₂} + (hf : ∀ x ∈ p, f x ∈ q) (x : p) : f.restrict hf x = ⟨f x, hf x.1 x.2⟩ := + rfl + +open Set in +lemma restrict_comp {p : Submodule R₁ M₁} {p₂ : Submodule R₂ M₂} {p₃ : Submodule R₃ M₃} + {f : M₁ →SL[σ₁₂] M₂} {g : M₂ →SL[σ₂₃] M₃} + (hf : MapsTo f p p₂) (hg : MapsTo g p₂ p₃) (hfg : MapsTo (g.comp f) p p₃ := hg.comp hf) : + (g.comp f).restrict hfg = (g.restrict hg).comp (f.restrict hf) := + rfl + +end ContinuousLinearMap + +end Restrict + namespace ContinuousLinearMap @[grind =] From 88d674086c6d708e1b01c8057e25976a15aa2973 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 13 May 2026 21:37:09 -0400 Subject: [PATCH 078/210] More API + move around --- .../Topology/Algebra/Module/LinearMap.lean | 112 ++++++++++++------ 1 file changed, 73 insertions(+), 39 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/LinearMap.lean b/Mathlib/Topology/Algebra/Module/LinearMap.lean index 0ec1ceb3faf5d2..743dd303c23f81 100644 --- a/Mathlib/Topology/Algebra/Module/LinearMap.lean +++ b/Mathlib/Topology/Algebra/Module/LinearMap.lean @@ -906,38 +906,6 @@ theorem toSpanSingleton_pow [TopologicalSpace R] [IsTopologicalRing R] (c : R) ( @[deprecated (since := "2025-12-18")] alias smulRight_one_pow := toSpanSingleton_pow -section - -variable {σ₂₁ : R₂ →+* R} [RingHomInvPair σ₁₂ σ₂₁] - -/-- Given a right inverse `f₂ : M₂ →L[R] M` to `f₁ : M →L[R] M₂`, -`projKerOfRightInverse f₁ f₂ h` is the projection `M →L[R] LinearMap.ker f₁` along -`LinearMap.range f₂`. -/ -def projKerOfRightInverse [IsTopologicalAddGroup M] (f₁ : M →SL[σ₁₂] M₂) (f₂ : M₂ →SL[σ₂₁] M) - (h : Function.RightInverse f₂ f₁) : M →L[R] LinearMap.ker (f₁ : M →ₛₗ[σ₁₂] M₂) := - (.id R M - f₂.comp f₁).codRestrict (LinearMap.ker f₁.toLinearMap) fun x => by simp [h (f₁ x)] - -@[simp] -theorem coe_projKerOfRightInverse_apply [IsTopologicalAddGroup M] (f₁ : M →SL[σ₁₂] M₂) - (f₂ : M₂ →SL[σ₂₁] M) (h : Function.RightInverse f₂ f₁) (x : M) : - (f₁.projKerOfRightInverse f₂ h x : M) = x - f₂ (f₁ x) := - rfl - -@[simp] -theorem projKerOfRightInverse_apply_idem [IsTopologicalAddGroup M] (f₁ : M →SL[σ₁₂] M₂) - (f₂ : M₂ →SL[σ₂₁] M) (h : Function.RightInverse f₂ f₁) (x : f₁.ker) : - f₁.projKerOfRightInverse f₂ h x = x := by - ext1 - simp - -@[simp] -theorem projKerOfRightInverse_comp_inv [IsTopologicalAddGroup M] (f₁ : M →SL[σ₁₂] M₂) - (f₂ : M₂ →SL[σ₂₁] M) (h : Function.RightInverse f₂ f₁) (y : M₂) : - f₁.projKerOfRightInverse f₂ h (f₂ y) = 0 := - Subtype.ext_iff.2 <| by simp [h y] - -end - end Ring section DivisionRing @@ -1280,9 +1248,31 @@ end Ring end Submodule +namespace ContinuousLinearMap + section Restrict -namespace ContinuousLinearMap +variable {R₁ R₂ R₃ : Type*} [Semiring R₁] [Semiring R₂] [Semiring R₃] + {σ₁₂ : R₁ →+* R₂} {σ₂₃ : R₂ →+* R₃} {σ₁₃ : R₁ →+* R₃} [RingHomCompTriple σ₁₂ σ₂₃ σ₁₃] + {M₁ M₂ M₃ : Type*} + [TopologicalSpace M₁] [AddCommMonoid M₁] [Module R₁ M₁] + [TopologicalSpace M₂] [AddCommMonoid M₂] [Module R₂ M₂] + [TopologicalSpace M₃] [AddCommMonoid M₃] [Module R₃ M₃] + +/-- The restriction of a linear map `f : M → M₂` to a submodule `p ⊆ M` gives a linear map +`p → M₂`. -/ +@[simps!] +def domRestrict (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₁ M₁) : p →SL[σ₁₂] M₂ := + f.comp p.subtypeL + +@[simp] +theorem toLinearMap_domRestrict (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₁ M₁) : + (f.domRestrict p).toLinearMap = f.toLinearMap.domRestrict p := + rfl + +lemma coe_domRestrict (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₁ M₁) : + ⇑(f.domRestrict p) = Set.restrict p f := + rfl /-- Restrict codomain of a continuous linear map. -/ def codRestrict (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₂ M₂) (h : ∀ x, f x ∈ p) : @@ -1317,10 +1307,8 @@ theorem coe_rangeRestrict [RingHomSurjective σ₁₂] (f : M₁ →SL[σ₁₂] /-- Restrict codomain of a continuous linear map. -/ def restrict (f : M₁ →SL[σ₁₂] M₂) {p : Submodule R₁ M₁} {q : Submodule R₂ M₂} - (h : ∀ x ∈ p, f x ∈ q) : - p →SL[σ₁₂] q where - toLinearMap := f.toLinearMap.restrict h - cont := f.continuous.restrict h + (h : ∀ x ∈ p, f x ∈ q) : p →SL[σ₁₂] q := + (f.domRestrict p).codRestrict q <| SetLike.forall.2 h @[simp, norm_cast] theorem toLinearMap_restrict {f : M₁ →SL[σ₁₂] M₂} {p : Submodule R₁ M₁} {q : Submodule R₂ M₂} @@ -1344,11 +1332,57 @@ lemma restrict_comp {p : Submodule R₁ M₁} {p₂ : Submodule R₂ M₂} {p₃ (g.comp f).restrict hfg = (g.restrict hg).comp (f.restrict hf) := rfl -end ContinuousLinearMap +theorem subtypeL_comp_restrict {f : M₁ →SL[σ₁₂] M₂} {p : Submodule R₁ M₁} {q : Submodule R₂ M₂} + (hf : ∀ x ∈ p, f x ∈ q) : q.subtypeL.comp (f.restrict hf) = f.domRestrict p := + rfl + +theorem restrict_eq_codRestrict_domRestrict {f : M₁ →SL[σ₁₂] M₂} {p : Submodule R₁ M₁} + {q : Submodule R₂ M₂} (hf : ∀ x ∈ p, f x ∈ q) : + f.restrict hf = (f.domRestrict p).codRestrict q fun x => hf x.1 x.2 := + rfl + +theorem restrict_eq_domRestrict_codRestrict {f : M₁ →SL[σ₁₂] M₂} {p : Submodule R₁ M₁} + {q : Submodule R₂ M₂} (hf : ∀ x, f x ∈ q) : + (f.restrict fun x _ => hf x) = (f.codRestrict q hf).domRestrict p := + rfl end Restrict -namespace ContinuousLinearMap +section + +variable {R₁ R₂ R₃ : Type*} [Ring R₁] [Ring R₂] + {σ₁₂ : R₁ →+* R₂} {σ₂₁ : R₂ →+* R₁} [RingHomInvPair σ₁₂ σ₂₁] + {M₁ M₂ : Type*} + [TopologicalSpace M₁] [AddCommGroup M₁] [Module R₁ M₁] + [TopologicalSpace M₂] [AddCommGroup M₂] [Module R₂ M₂] + +/-- Given a right inverse `f₂ : M₂ →L[R] M₁` to `f₁ : M₁ →L[R] M₂`, +`projKerOfRightInverse f₁ f₂ h` is the projection `M₁ →L[R] LinearMap.ker f₁` along +`LinearMap.range f₂`. -/ +def projKerOfRightInverse [IsTopologicalAddGroup M₁] (f₁ : M₁ →SL[σ₁₂] M₂) (f₂ : M₂ →SL[σ₂₁] M₁) + (h : Function.RightInverse f₂ f₁) : M₁ →L[R₁] LinearMap.ker (f₁ : M₁ →ₛₗ[σ₁₂] M₂) := + (.id R₁ M₁ - f₂.comp f₁).codRestrict (LinearMap.ker f₁.toLinearMap) fun x => by simp [h (f₁ x)] + +@[simp] +theorem coe_projKerOfRightInverse_apply [IsTopologicalAddGroup M₁] (f₁ : M₁ →SL[σ₁₂] M₂) + (f₂ : M₂ →SL[σ₂₁] M₁) (h : Function.RightInverse f₂ f₁) (x : M₁) : + (f₁.projKerOfRightInverse f₂ h x : M₁) = x - f₂ (f₁ x) := + rfl + +@[simp] +theorem projKerOfRightInverse_apply_idem [IsTopologicalAddGroup M₁] (f₁ : M₁ →SL[σ₁₂] M₂) + (f₂ : M₂ →SL[σ₂₁] M₁) (h : Function.RightInverse f₂ f₁) (x : f₁.ker) : + f₁.projKerOfRightInverse f₂ h x = x := by + ext1 + simp + +@[simp] +theorem projKerOfRightInverse_comp_inv [IsTopologicalAddGroup M₁] (f₁ : M₁ →SL[σ₁₂] M₂) + (f₂ : M₂ →SL[σ₂₁] M₁) (h : Function.RightInverse f₂ f₁) (y : M₂) : + f₁.projKerOfRightInverse f₂ h (f₂ y) = 0 := + Subtype.ext_iff.2 <| by simp [h y] + +end @[grind =] theorem isIdempotentElem_toLinearMap_iff {R M : Type*} [Semiring R] [TopologicalSpace M] From 25c3df919661af617d2f10c38ab99ff93866e439 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 13 May 2026 23:13:47 -0400 Subject: [PATCH 079/210] fix in cohomology --- Mathlib/Algebra/Category/ContinuousCohomology/Basic.lean | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Mathlib/Algebra/Category/ContinuousCohomology/Basic.lean b/Mathlib/Algebra/Category/ContinuousCohomology/Basic.lean index ca58f2c132d596..a95e7ca4c0423c 100644 --- a/Mathlib/Algebra/Category/ContinuousCohomology/Basic.lean +++ b/Mathlib/Algebra/Category/ContinuousCohomology/Basic.lean @@ -143,10 +143,8 @@ def invariants : Action (TopModuleCat R) G ⥤ TopModuleCat R where add_mem' hx hy g := by simp [hx g, hy g] zero_mem' := by simp smul_mem' r x hx g := by simp [hx g] : Submodule R M.V } - map f := TopModuleCat.ofHom - { toLinearMap := f.hom.hom.restrict fun x hx g ↦ - congr($(f.comm g) x).symm.trans congr(f.hom.hom $(hx g)) - cont := continuous_induced_rng.mpr (f.hom.hom.2.comp continuous_subtype_val) } + map f := TopModuleCat.ofHom <| f.hom.hom.restrict fun x hx g ↦ + congr($(f.comm g) x).symm.trans congr(f.hom.hom $(hx g)) instance : (invariants R G).Linear R where instance : (invariants R G).Additive where From c92ead73d090690d7f21db7fdf5f6e591ff80d7e Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 13 May 2026 23:15:26 -0400 Subject: [PATCH 080/210] fixes --- Mathlib/Analysis/InnerProductSpace/Spectrum.lean | 3 +-- Mathlib/LinearAlgebra/Eigenspace/Zero.lean | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Mathlib/Analysis/InnerProductSpace/Spectrum.lean b/Mathlib/Analysis/InnerProductSpace/Spectrum.lean index 256a157f96734b..40db395b63cfff 100644 --- a/Mathlib/Analysis/InnerProductSpace/Spectrum.lean +++ b/Mathlib/Analysis/InnerProductSpace/Spectrum.lean @@ -443,8 +443,7 @@ theorem orthogonalComplement_iSup_eigenspaces_eq_bot (hT : IsCompactOperator T) (hT' : T.IsSymmetric) : (⨆ μ, eigenspace (T : Module.End 𝕜 E) μ)ᗮ = ⊥ := by let S : (⨆ μ, eigenspace T μ : Submodule 𝕜 E)ᗮ →L[𝕜] (⨆ μ, eigenspace T μ : Submodule 𝕜 E)ᗮ := - { __ := T.restrict hT'.orthogonalComplement_iSup_eigenspaces_invariant - cont := by fun_prop } + T.restrict hT'.orthogonalComplement_iSup_eigenspaces_invariant have hS_compact : IsCompactOperator S := hT.restrict' hT'.orthogonalComplement_iSup_eigenspaces_invariant have hS_symm : S.IsSymmetric := diff --git a/Mathlib/LinearAlgebra/Eigenspace/Zero.lean b/Mathlib/LinearAlgebra/Eigenspace/Zero.lean index 4f4e2d1d305bdc..06ff4584c823d5 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Zero.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Zero.lean @@ -172,7 +172,7 @@ lemma finrank_maxGenEigenspace_zero_eq (φ : Module.End K M) : LinearEquiv.symm_symm, Submodule.coe_prodEquivOfIsCompl, coe_comp, LinearEquiv.coe_coe, Function.comp_apply, coprod_apply, Submodule.coe_subtype, map_add, Sum.forall, Sum.elim_inl, map_zero, ZeroMemClass.coe_zero, add_zero, LinearEquiv.eq_symm_apply, and_self, - Submodule.coe_prodEquivOfIsCompl', restrict_coe_apply, implies_true, Sum.elim_inr, zero_add, + Submodule.coe_prodEquivOfIsCompl', coe_restrict_apply, implies_true, Sum.elim_inr, zero_add, e, V, W, ψ, F, G, b] rw [← e.symm.charpoly_conj φ, ← hψ, charpoly_prodMap, natTrailingDegree_mul (charpoly_monic _).ne_zero (charpoly_monic _).ne_zero] From db6b8516cf7d8f5b75748a8f24c9e4f7997a1db5 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 14 May 2026 08:15:46 -0400 Subject: [PATCH 081/210] notation --- Mathlib/Topology/Algebra/Module/LinearMap.lean | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/LinearMap.lean b/Mathlib/Topology/Algebra/Module/LinearMap.lean index 33554722cccb1c..e1ec60c82cb494 100644 --- a/Mathlib/Topology/Algebra/Module/LinearMap.lean +++ b/Mathlib/Topology/Algebra/Module/LinearMap.lean @@ -528,7 +528,7 @@ theorem add_comp [ContinuousAdd M₃] (g₁ g₂ : M₂ →SL[σ₂₃] M₃) (f theorem comp_finsetSum {ι : Type*} {s : Finset ι} [ContinuousAdd M₂] [ContinuousAdd M₃] (g : M₂ →SL[σ₂₃] M₃) - (f : ι → M₁ →SL[σ₁₂] M₂) : g ∘SL (∑ i ∈ s, f i) = ∑ i ∈ s, g.comp (f i) := by + (f : ι → M₁ →SL[σ₁₂] M₂) : g ∘SL (∑ i ∈ s, f i) = ∑ i ∈ s, g ∘SL (f i) := by ext simp @@ -536,7 +536,7 @@ theorem comp_finsetSum {ι : Type*} {s : Finset ι} theorem finsetSum_comp {ι : Type*} {s : Finset ι} [ContinuousAdd M₃] (g : ι → M₂ →SL[σ₂₃] M₃) - (f : M₁ →SL[σ₁₂] M₂) : (∑ i ∈ s, g i) ∘SL f = ∑ i ∈ s, (g i).comp f := by + (f : M₁ →SL[σ₁₂] M₂) : (∑ i ∈ s, g i) ∘SL f = ∑ i ∈ s, (g i) ∘SL f := by ext simp only [coe_comp', coe_sum', Function.comp_apply, Finset.sum_apply] @@ -704,7 +704,7 @@ variable [Module R₁ M₂] [TopologicalSpace R₁] [ContinuousSMul R₁ M₂] theorem smulRight_comp_smulRight {M₃ : Type*} [AddCommMonoid M₃] [Module R₁ M₃] [TopologicalSpace M₃] [ContinuousSMul R₁ M₃] (f : M₃ →L[R₁] R₁) (g : M₁ →L[R₁] R₁) {x : M₂} - {y : M₃} : (smulRight f x).comp (smulRight g y) = smulRight g (f y • x) := by + {y : M₃} : (smulRight f x) ∘L (smulRight g y) = smulRight g (f y • x) := by ext simp @@ -1267,7 +1267,7 @@ variable {R₁ R₂ R₃ : Type*} [Semiring R₁] [Semiring R₂] [Semiring R₃ `p → M₂`. -/ @[simps!] def domRestrict (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₁ M₁) : p →SL[σ₁₂] M₂ := - f.comp p.subtypeL + f ∘SL p.subtypeL @[simp] theorem toLinearMap_domRestrict (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₁ M₁) : @@ -1332,12 +1332,12 @@ theorem restrict_apply {f : M₁ →SL[σ₁₂] M₂} {p : Submodule R₁ M₁} open Set in lemma restrict_comp {p : Submodule R₁ M₁} {p₂ : Submodule R₂ M₂} {p₃ : Submodule R₃ M₃} {f : M₁ →SL[σ₁₂] M₂} {g : M₂ →SL[σ₂₃] M₃} - (hf : MapsTo f p p₂) (hg : MapsTo g p₂ p₃) (hfg : MapsTo (g.comp f) p p₃ := hg.comp hf) : - (g.comp f).restrict hfg = (g.restrict hg).comp (f.restrict hf) := + (hf : MapsTo f p p₂) (hg : MapsTo g p₂ p₃) (hfg : MapsTo (g ∘SL f) p p₃ := hg.comp hf) : + (g ∘SL f).restrict hfg = (g.restrict hg) ∘SL (f.restrict hf) := rfl theorem subtypeL_comp_restrict {f : M₁ →SL[σ₁₂] M₂} {p : Submodule R₁ M₁} {q : Submodule R₂ M₂} - (hf : ∀ x ∈ p, f x ∈ q) : q.subtypeL.comp (f.restrict hf) = f.domRestrict p := + (hf : ∀ x ∈ p, f x ∈ q) : q.subtypeL ∘SL (f.restrict hf) = f.domRestrict p := rfl theorem restrict_eq_codRestrict_domRestrict {f : M₁ →SL[σ₁₂] M₂} {p : Submodule R₁ M₁} @@ -1365,7 +1365,7 @@ variable {R₁ R₂ R₃ : Type*} [Ring R₁] [Ring R₂] `LinearMap.range f₂`. -/ def projKerOfRightInverse [IsTopologicalAddGroup M₁] (f₁ : M₁ →SL[σ₁₂] M₂) (f₂ : M₂ →SL[σ₂₁] M₁) (h : Function.RightInverse f₂ f₁) : M₁ →L[R₁] LinearMap.ker (f₁ : M₁ →ₛₗ[σ₁₂] M₂) := - (.id R₁ M₁ - f₂.comp f₁).codRestrict (LinearMap.ker f₁.toLinearMap) fun x => by simp [h (f₁ x)] + (.id R₁ M₁ - f₂ ∘SL f₁).codRestrict (LinearMap.ker f₁.toLinearMap) fun x => by simp [h (f₁ x)] @[simp] theorem coe_projKerOfRightInverse_apply [IsTopologicalAddGroup M₁] (f₁ : M₁ →SL[σ₁₂] M₂) From b61bb8c10354e0b1a560e3f91b81cd83c6bb9f52 Mon Sep 17 00:00:00 2001 From: sharky564 Date: Fri, 15 May 2026 00:12:38 +1000 Subject: [PATCH 082/210] Incorporated PR feedback --- .../Topology/Algebra/Module/Complement.lean | 47 +++++++------------ 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 2de186c23ad9d1..291a94c11946a5 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -399,7 +399,7 @@ variable [IsTopologicalAddGroup M] /-- Two submodules `p` and `q` are topological complements if and only if the algebraic equivalence `p.prodEquivOfIsCompl q h` is continuous in the inverse direction. -/ -theorem IsCompl.isTopCompl_iff_continuous_prodEquiv_symm (h : IsCompl p q) : +theorem IsCompl.isTopCompl_iff_continuous_symm_prodEquivOfIsCompl (h : IsCompl p q) : IsTopCompl p q ↔ Continuous (p.prodEquivOfIsCompl q h).symm := ⟨fun hTop ↦ ((p.projectionOntoL q hTop).prod (q.projectionOntoL p hTop.symm)).continuous.congr fun x ↦ (prodEquivOfIsCompl_symm_apply h x).symm, @@ -412,30 +412,24 @@ theorem continuous_prodEquivOfIsCompl (h : IsCompl p q) : Continuous (p.prodEqui /-- Two submodules `p` and `q` are topological complements if and only if the algebraic equivalence `p.prodEquivOfIsCompl q h` is a homeomorphism. -/ -theorem IsCompl.isTopCompl_iff_isHomeomorph_prodEquiv (h : IsCompl p q) : +theorem IsCompl.isTopCompl_iff_isHomeomorph_prodEquivOfIsCompl (h : IsCompl p q) : IsTopCompl p q ↔ IsHomeomorph (p.prodEquivOfIsCompl q h) := by - rw [(p.prodEquivOfIsCompl q h).isHomeomorph_iff, isTopCompl_iff_continuous_prodEquiv_symm, - and_iff_right] + rw [(p.prodEquivOfIsCompl q h).isHomeomorph_iff, + isTopCompl_iff_continuous_symm_prodEquivOfIsCompl, and_iff_right] exact continuous_prodEquivOfIsCompl h variable (p q) in /-- If two submodules `p` and `q` are topological complements, then the algebraic equivalence -`p.prodEquivOfIsCompl q h.isCompl` is a homeomorphism, bundled as a continuous linear equivalence. --/ +`p.prodEquivOfIsCompl q h.isCompl` is a homeomorphism, bundled as a continuous linear +equivalence. -/ noncomputable def prodEquivOfIsTopCompl (h : IsTopCompl p q) : (p × q) ≃L[R] M := { p.prodEquivOfIsCompl q h.isCompl with continuous_toFun := continuous_prodEquivOfIsCompl h.isCompl - continuous_invFun := h.isCompl.isTopCompl_iff_continuous_prodEquiv_symm.mp h } - -@[simp] -theorem coe_prodEquivOfIsTopCompl (h : IsTopCompl p q) : - (prodEquivOfIsTopCompl p q h : (p × q) →ₗ[R] M) = p.prodEquivOfIsCompl q h.isCompl := - rfl + continuous_invFun := h.isCompl.isTopCompl_iff_continuous_symm_prodEquivOfIsCompl.mp h } @[simp] -theorem coe_prodEquivOfIsTopCompl_symm (h : IsTopCompl p q) : - ((prodEquivOfIsTopCompl p q h).symm : M →ₗ[R] p × q) = - (p.prodEquivOfIsCompl q h.isCompl).symm := +theorem toLinearEquiv_prodEquivOfIsTopCompl (h : IsTopCompl p q) : + (prodEquivOfIsTopCompl p q h : (p × q) ≃ₗ[R] M) = p.prodEquivOfIsCompl q h.isCompl := rfl @[simp] @@ -451,7 +445,7 @@ theorem prodEquivOfIsTopCompl_symm_apply (h : IsTopCompl p q) (x : M) : /-- Two submodules `p` and `q` are topological complements if and only if the algebraic equivalence `p.quotientEquivOfIsCompl q h` is continuous. -/ -theorem IsCompl.isTopCompl_iff_continuous_quotientEquiv (h : IsCompl p q) : +theorem IsCompl.isTopCompl_iff_continuous_quotientEquivOfIsCompl (h : IsCompl p q) : IsTopCompl p q ↔ Continuous (p.quotientEquivOfIsCompl q h) := by have hproj : ⇑(p.quotientEquivOfIsCompl q h) ∘ ⇑p.mkQ = ⇑(q.projectionOnto p h.symm) := by funext; simp @@ -464,18 +458,12 @@ variable (p q) in equivalence. -/ noncomputable def quotientEquivOfIsTopCompl (h : IsTopCompl p q) : (M ⧸ p) ≃L[R] q := { p.quotientEquivOfIsCompl q h.isCompl with - continuous_toFun := h.isCompl.isTopCompl_iff_continuous_quotientEquiv.mp h + continuous_toFun := h.isCompl.isTopCompl_iff_continuous_quotientEquivOfIsCompl.mp h continuous_invFun := (p.mkQL.comp q.subtypeL).continuous } @[simp] -theorem coe_quotientEquivOfIsTopCompl (h : IsTopCompl p q) : - (quotientEquivOfIsTopCompl p q h : (M ⧸ p) →ₗ[R] q) = p.quotientEquivOfIsCompl q h.isCompl := - rfl - -@[simp] -theorem coe_quotientEquivOfIsTopCompl_symm (h : IsTopCompl p q) : - ((quotientEquivOfIsTopCompl p q h).symm : q →ₗ[R] M ⧸ p) = - (p.quotientEquivOfIsCompl q h.isCompl).symm := +theorem toLinearEquiv_quotientEquivOfIsTopCompl (h : IsTopCompl p q) : + (quotientEquivOfIsTopCompl p q h : (M ⧸ p) ≃ₗ[R] q) = p.quotientEquivOfIsCompl q h.isCompl := rfl theorem quotientEquivOfIsTopCompl_apply (h : IsTopCompl p q) (x : M ⧸ p) : @@ -489,8 +477,7 @@ theorem quotientEquivOfIsTopCompl_symm_apply (h : IsTopCompl p q) (y : q) : @[simp] theorem quotientEquivOfIsTopCompl_apply_mk (h : IsTopCompl p q) (x : M) : - quotientEquivOfIsTopCompl p q h (Submodule.Quotient.mk x) = - q.projectionOnto p h.isCompl.symm x := + quotientEquivOfIsTopCompl p q h (Quotient.mk x) = q.projectionOnto p h.isCompl.symm x := quotientEquivOfIsCompl_apply_mk h.isCompl x end ContinuousLinearEquiv @@ -505,12 +492,14 @@ variable {R : Type*} [Ring R] {E F : Type*} {p q : Submodule R E} /-- Given continuous linear maps `φ : p →L[R] F` and `ψ : q →L[R] F` from topological complement -submodules of `E`, the induced continuous linear map `E →L[R] F`. -/ +submodules of `E`, the induced continuous linear map `E →L[R] F`. + +This is the continuous version of `LinearMap.ofIsCompl`. -/ noncomputable def ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : E →L[R] F := φ ∘L p.projectionOntoL q h + ψ ∘L q.projectionOntoL p h.symm @[simp] -theorem coe_ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : +theorem toLinearMap_ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : (ofIsTopCompl h φ ψ : E →ₗ[R] F) = LinearMap.ofIsCompl h.isCompl φ ψ := by rw [LinearMap.ofIsCompl_eq_add] rfl From 34bd4ea689c6b9e956e446bcebf75c0d6670a6a9 Mon Sep 17 00:00:00 2001 From: sharky564 Date: Fri, 15 May 2026 00:31:35 +1000 Subject: [PATCH 083/210] added coprod --- Mathlib/Topology/Algebra/Module/Complement.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 291a94c11946a5..e5765b19a99a0e 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -498,6 +498,10 @@ This is the continuous version of `LinearMap.ofIsCompl`. -/ noncomputable def ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : E →L[R] F := φ ∘L p.projectionOntoL q h + ψ ∘L q.projectionOntoL p h.symm +theorem ofIsTopCompl_eq_coprod (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : + ofIsTopCompl h φ ψ = φ.coprod ψ ∘L (prodEquivOfIsTopCompl p q h).symm := by + ext x; simp [ofIsTopCompl] + @[simp] theorem toLinearMap_ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : (ofIsTopCompl h φ ψ : E →ₗ[R] F) = LinearMap.ofIsCompl h.isCompl φ ψ := by From ce30d61d66eab0e24a83dca61878756137ba42f6 Mon Sep 17 00:00:00 2001 From: sharky564 Date: Fri, 15 May 2026 00:39:55 +1000 Subject: [PATCH 084/210] Simplified --- Mathlib/Topology/Algebra/Module/Complement.lean | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index e5765b19a99a0e..ad27c92766f5b8 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -496,16 +496,12 @@ submodules of `E`, the induced continuous linear map `E →L[R] F`. This is the continuous version of `LinearMap.ofIsCompl`. -/ noncomputable def ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : E →L[R] F := - φ ∘L p.projectionOntoL q h + ψ ∘L q.projectionOntoL p h.symm + φ.coprod ψ ∘L ↑(prodEquivOfIsTopCompl p q h).symm -theorem ofIsTopCompl_eq_coprod (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : - ofIsTopCompl h φ ψ = φ.coprod ψ ∘L (prodEquivOfIsTopCompl p q h).symm := by - ext x; simp [ofIsTopCompl] @[simp] theorem toLinearMap_ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : (ofIsTopCompl h φ ψ : E →ₗ[R] F) = LinearMap.ofIsCompl h.isCompl φ ψ := by - rw [LinearMap.ofIsCompl_eq_add] rfl @[simp] From 9dc4589ec9f053ad6b97b28ffdf9ed05d9743a97 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 14 May 2026 12:03:38 -0400 Subject: [PATCH 085/210] domRestrict_comp_codRestrict --- Mathlib/Topology/Algebra/Module/LinearMap.lean | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Mathlib/Topology/Algebra/Module/LinearMap.lean b/Mathlib/Topology/Algebra/Module/LinearMap.lean index e1ec60c82cb494..03da392119bbd9 100644 --- a/Mathlib/Topology/Algebra/Module/LinearMap.lean +++ b/Mathlib/Topology/Algebra/Module/LinearMap.lean @@ -1299,6 +1299,12 @@ theorem ker_codRestrict (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₂ M₂ ker (f.codRestrict p h : M₁ →ₛₗ[σ₁₂] p) = ker (f : M₁ →ₛₗ[σ₁₂] M₂) := (f : M₁ →ₛₗ[σ₁₂] M₂).ker_codRestrict p h +@[simp] +theorem domRestrict_comp_codRestrict (g : M₂ →SL[σ₂₃] M₃) (f : M₁ →SL[σ₁₂] M₂) + (p : Submodule R₂ M₂) (h : ∀ x, f x ∈ p) : + g.domRestrict p ∘SL f.codRestrict p h = g ∘SL f := + rfl + /-- Restrict the codomain of a continuous linear map `f` to `f.range`. -/ abbrev rangeRestrict [RingHomSurjective σ₁₂] (f : M₁ →SL[σ₁₂] M₂) := f.codRestrict (LinearMap.range (f : M₁ →ₛₗ[σ₁₂] M₂)) (LinearMap.mem_range_self _) From f07300a537d62488367d45e31971ab997d31d895 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 14 May 2026 12:14:35 -0400 Subject: [PATCH 086/210] ++ --- Mathlib/Topology/Algebra/Module/LinearMap.lean | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/LinearMap.lean b/Mathlib/Topology/Algebra/Module/LinearMap.lean index 03da392119bbd9..0a787aced787b4 100644 --- a/Mathlib/Topology/Algebra/Module/LinearMap.lean +++ b/Mathlib/Topology/Algebra/Module/LinearMap.lean @@ -1284,9 +1284,13 @@ def codRestrict (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₂ M₂) (h : cont := f.continuous.subtype_mk _ toLinearMap := (f : M₁ →ₛₗ[σ₁₂] M₂).codRestrict p h -@[norm_cast] +@[simp, norm_cast] +theorem toLinearMap_codRestrict (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₂ M₂) (h : ∀ x, f x ∈ p) : + (f.codRestrict p h).toLinearMap = f.toLinearMap.codRestrict p h := + rfl + theorem coe_codRestrict (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₂ M₂) (h : ∀ x, f x ∈ p) : - (f.codRestrict p h : M₁ →ₛₗ[σ₁₂] p) = (f : M₁ →ₛₗ[σ₁₂] M₂).codRestrict p h := + (f.codRestrict p h : M₁ → p) = Set.codRestrict (f : M₁ → M₂) p h := rfl @[simp] From 28a25983e60dc9136a05cc2334e3ca6eae60fd2d Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 14 May 2026 12:37:23 -0400 Subject: [PATCH 087/210] Comments in the proof --- .../Operator/Perturbation/StrictByFinite.lean | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 6be23264a016f1..8157ec4a527b1f 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -55,13 +55,22 @@ theorem step1_foward (A : Submodule 𝕜 E) (K : Submodule 𝕜 E) (A_closed : I [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (K_disj_A : Disjoint K A) : IsClosedEmbedding (restrict A K.mkQ) := by constructor - · rcases K_disj_A.exists_isCompl with ⟨S, K_le_S, S_compl_A⟩ + · -- We show that `restrict A K.mkQ` is an embedding by exhibiting a continuous left inverse. + -- Fix `S` an algebraic complement of `A` containing `K`. + rcases K_disj_A.exists_isCompl with ⟨S, K_le_S, S_compl_A⟩ + -- Because `A` is closed with finite codimension, `S` is in fact a topological complement + -- of `A`. replace S_compl_A : IsTopCompl S A := S_compl_A.symm.isTopCompl_of_finiteDimensional_quotient A_closed |>.symm + -- Thus the projection onto `A` along `S` is continuous, and it vanishes on `K`. + -- Hence it defines a map `E ⧸ K →L[𝕜] A`, which is our left inverse. let s : E ⧸ K →L[𝕜] A := K.liftQL (A.projectionOntoL S S_compl_A.symm) (by simpa) have leftInv : LeftInverse s (restrict A K.mkQ) := fun x ↦ by simp [s] refine .of_leftInverse leftInv s.continuous (by fun_prop) - · rw [← K.isQuotientMap_mkQ.isClosed_preimage, range_restrict, ← Submodule.map_coe, + · -- The subspace `K.mkQ ⁻¹' K.mkQ '' A` contains the closed and finite codimension subspace `A`, + -- hence it is closed. By definition of the quotient topology, this shows that + -- `restrict A K.mkQ` has closed range. + rw [← K.isQuotientMap_mkQ.isClosed_preimage, range_restrict, ← Submodule.map_coe, ← Submodule.comap_coe K.mkQ] exact isClosed_mono_of_finiteDimensional_quotient A_closed (le_comap_map _ A) @@ -104,17 +113,24 @@ a closed embedding. theorem step2_forward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_strict : IsStrictMap u) (h_closed : IsClosed (range u)) : IsClosedEmbedding (restrict A u) := by + -- Denote by `π : E → E ⧸ u.ker` the quotient map. Since `u.ker` is disjoint from `A`, we know + -- from step 1 that `restrict A π` is a closed embedding. + let π : E →L[𝕜] E ⧸ u.ker := u.ker.mkQL + have π_restr_clemb : IsClosedEmbedding (restrict A π) := + step1_foward A u.ker A_closed h_ker + -- But we can factor `restrict A u` as `u' ∘ restrict A π`, where `u' : E ⧸ u.ker → F` + -- is the injection induced by `u`. Thus, it remains to show that `u'` is also a closed embedding. let u' : E ⧸ u.ker →L[𝕜] F := u.ker.liftQL u le_rfl + have eq : restrict A u = u' ∘ restrict A π := by ext x; simp [π, u'] have u'_clemb : IsClosedEmbedding u' := by + -- But strictness of `u` means precisely that `u'` is an embedding, + -- and we assumed that `u` (hence `u'`) has closed range. + -- Hence, we are done. constructor · have : Injective u' := by simp [u', ← LinearMap.ker_eq_bot, ker_liftQ_eq_bot] simpa [isEmbedding_iff_isStrictMap_injective, this, and_true, u.ker.isQuotientMap_mkQL.isStrictMap_iff] · simpa [u', ← LinearMap.coe_range, Submodule.range_liftQ] - let π : E →L[𝕜] E ⧸ u.ker := u.ker.mkQL - have π_restr_clemb : IsClosedEmbedding (restrict A π) := - step1_foward A u.ker A_closed h_ker - have eq : restrict A u = u' ∘ restrict A π := by ext x; simp [π, u'] exact eq ▸ u'_clemb.comp π_restr_clemb theorem step2_backward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) From 6de7d312fcf80c9b220b8c5df2047d3516d8e034 Mon Sep 17 00:00:00 2001 From: sharky564 Date: Fri, 15 May 2026 02:58:10 +1000 Subject: [PATCH 088/210] PR cleanups --- Mathlib/Topology/Algebra/Module/Complement.lean | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index ad27c92766f5b8..fdba199edf9f30 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -397,7 +397,7 @@ section ContinuousLinearEquiv variable [IsTopologicalAddGroup M] -/-- Two submodules `p` and `q` are topological complements if and only if the algebraic equivalence +/-- Two submodules `p` and `q` are topological complements if and only if the linear equivalence `p.prodEquivOfIsCompl q h` is continuous in the inverse direction. -/ theorem IsCompl.isTopCompl_iff_continuous_symm_prodEquivOfIsCompl (h : IsCompl p q) : IsTopCompl p q ↔ Continuous (p.prodEquivOfIsCompl q h).symm := @@ -410,7 +410,7 @@ complementary submodules is always continuous as a map `p × q → M`. -/ theorem continuous_prodEquivOfIsCompl (h : IsCompl p q) : Continuous (p.prodEquivOfIsCompl q h) := (continuous_subtype_val.comp continuous_fst).add (continuous_subtype_val.comp continuous_snd) -/-- Two submodules `p` and `q` are topological complements if and only if the algebraic equivalence +/-- Two submodules `p` and `q` are topological complements if and only if the linear equivalence `p.prodEquivOfIsCompl q h` is a homeomorphism. -/ theorem IsCompl.isTopCompl_iff_isHomeomorph_prodEquivOfIsCompl (h : IsCompl p q) : IsTopCompl p q ↔ IsHomeomorph (p.prodEquivOfIsCompl q h) := by @@ -419,7 +419,7 @@ theorem IsCompl.isTopCompl_iff_isHomeomorph_prodEquivOfIsCompl (h : IsCompl p q) exact continuous_prodEquivOfIsCompl h variable (p q) in -/-- If two submodules `p` and `q` are topological complements, then the algebraic equivalence +/-- If two submodules `p` and `q` are topological complements, then the linear equivalence `p.prodEquivOfIsCompl q h.isCompl` is a homeomorphism, bundled as a continuous linear equivalence. -/ noncomputable def prodEquivOfIsTopCompl (h : IsTopCompl p q) : (p × q) ≃L[R] M := @@ -443,7 +443,7 @@ theorem prodEquivOfIsTopCompl_symm_apply (h : IsTopCompl p q) (x : M) : ((p.projectionOntoL q h x, q.projectionOntoL p h.symm x) : p × q) := prodEquivOfIsCompl_symm_apply h.isCompl x -/-- Two submodules `p` and `q` are topological complements if and only if the algebraic equivalence +/-- Two submodules `p` and `q` are topological complements if and only if the linear equivalence `p.quotientEquivOfIsCompl q h` is continuous. -/ theorem IsCompl.isTopCompl_iff_continuous_quotientEquivOfIsCompl (h : IsCompl p q) : IsTopCompl p q ↔ Continuous (p.quotientEquivOfIsCompl q h) := by @@ -453,7 +453,7 @@ theorem IsCompl.isTopCompl_iff_continuous_quotientEquivOfIsCompl (h : IsCompl p exact ⟨IsTopCompl.symm, IsTopCompl.symm⟩ variable (p q) in -/-- If two submodules `p` and `q` are topological complements, then the algebraic equivalence +/-- If two submodules `p` and `q` are topological complements, then the linear equivalence `p.quotientEquivOfIsCompl q h.isCompl` is a homeomorphism, bundled as a continuous linear equivalence. -/ noncomputable def quotientEquivOfIsTopCompl (h : IsTopCompl p q) : (M ⧸ p) ≃L[R] q := @@ -498,6 +498,9 @@ This is the continuous version of `LinearMap.ofIsCompl`. -/ noncomputable def ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : E →L[R] F := φ.coprod ψ ∘L ↑(prodEquivOfIsTopCompl p q h).symm +theorem ofIsTopCompl_eq_add (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : + ofIsTopCompl h φ ψ = φ ∘L p.projectionOntoL q h + ψ ∘L q.projectionOntoL p h.symm := by + ext; simp [ofIsTopCompl] @[simp] theorem toLinearMap_ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : From fc127ac5d97232f61f5683910b3156ab30f24b3b Mon Sep 17 00:00:00 2001 From: sharky564 Date: Fri, 15 May 2026 03:33:59 +1000 Subject: [PATCH 089/210] PR cleanups --- .../Topology/Algebra/Module/Complement.lean | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index fdba199edf9f30..1b6f1c61107ce4 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -397,21 +397,21 @@ section ContinuousLinearEquiv variable [IsTopologicalAddGroup M] -/-- Two submodules `p` and `q` are topological complements if and only if the linear equivalence -`p.prodEquivOfIsCompl q h` is continuous in the inverse direction. -/ +/-- Two complementary submodules are topological complements if and only if the linear equivalence +`Submodule.prodEquivOfIsCompl` is continuous in the inverse direction. -/ theorem IsCompl.isTopCompl_iff_continuous_symm_prodEquivOfIsCompl (h : IsCompl p q) : IsTopCompl p q ↔ Continuous (p.prodEquivOfIsCompl q h).symm := ⟨fun hTop ↦ ((p.projectionOntoL q hTop).prod (q.projectionOntoL p hTop.symm)).continuous.congr fun x ↦ (prodEquivOfIsCompl_symm_apply h x).symm, fun hCont ↦ ⟨h, continuous_subtype_val.comp <| continuous_fst.comp hCont⟩⟩ -/-- The algebraic equivalence `p.prodEquivOfIsCompl q h : p × q ≃ₗ[R] M` from a pair of -complementary submodules is always continuous as a map `p × q → M`. -/ +/-- The linear equivalence `Submodule.prodEquivOfIsCompl` from a pair of complementary submodules is +always continuous. -/ theorem continuous_prodEquivOfIsCompl (h : IsCompl p q) : Continuous (p.prodEquivOfIsCompl q h) := (continuous_subtype_val.comp continuous_fst).add (continuous_subtype_val.comp continuous_snd) -/-- Two submodules `p` and `q` are topological complements if and only if the linear equivalence -`p.prodEquivOfIsCompl q h` is a homeomorphism. -/ +/-- Two complementary submodules are topological complements if and only if the linear equivalence +`Submodule.prodEquivOfIsCompl` is a homeomorphism. -/ theorem IsCompl.isTopCompl_iff_isHomeomorph_prodEquivOfIsCompl (h : IsCompl p q) : IsTopCompl p q ↔ IsHomeomorph (p.prodEquivOfIsCompl q h) := by rw [(p.prodEquivOfIsCompl q h).isHomeomorph_iff, @@ -419,9 +419,8 @@ theorem IsCompl.isTopCompl_iff_isHomeomorph_prodEquivOfIsCompl (h : IsCompl p q) exact continuous_prodEquivOfIsCompl h variable (p q) in -/-- If two submodules `p` and `q` are topological complements, then the linear equivalence -`p.prodEquivOfIsCompl q h.isCompl` is a homeomorphism, bundled as a continuous linear -equivalence. -/ +/-- If two submodules are topological complements, then the linear equivalence +`Submodule.prodEquivOfIsCompl` is a homeomorphism, bundled as a continuous linear equivalence. -/ noncomputable def prodEquivOfIsTopCompl (h : IsTopCompl p q) : (p × q) ≃L[R] M := { p.prodEquivOfIsCompl q h.isCompl with continuous_toFun := continuous_prodEquivOfIsCompl h.isCompl @@ -443,8 +442,8 @@ theorem prodEquivOfIsTopCompl_symm_apply (h : IsTopCompl p q) (x : M) : ((p.projectionOntoL q h x, q.projectionOntoL p h.symm x) : p × q) := prodEquivOfIsCompl_symm_apply h.isCompl x -/-- Two submodules `p` and `q` are topological complements if and only if the linear equivalence -`p.quotientEquivOfIsCompl q h` is continuous. -/ +/-- Two complementary submodules are topological complements if and only if the linear equivalence +`Submodule.quotientEquivOfIsCompl` is continuous. -/ theorem IsCompl.isTopCompl_iff_continuous_quotientEquivOfIsCompl (h : IsCompl p q) : IsTopCompl p q ↔ Continuous (p.quotientEquivOfIsCompl q h) := by have hproj : ⇑(p.quotientEquivOfIsCompl q h) ∘ ⇑p.mkQ = ⇑(q.projectionOnto p h.symm) := by @@ -453,8 +452,8 @@ theorem IsCompl.isTopCompl_iff_continuous_quotientEquivOfIsCompl (h : IsCompl p exact ⟨IsTopCompl.symm, IsTopCompl.symm⟩ variable (p q) in -/-- If two submodules `p` and `q` are topological complements, then the linear equivalence -`p.quotientEquivOfIsCompl q h.isCompl` is a homeomorphism, bundled as a continuous linear +/-- If two submodules are topological complements, then the linear equivalence +`Submodule.quotientEquivOfIsCompl` is a homeomorphism, bundled as a continuous linear equivalence. -/ noncomputable def quotientEquivOfIsTopCompl (h : IsTopCompl p q) : (M ⧸ p) ≃L[R] q := { p.quotientEquivOfIsCompl q h.isCompl with @@ -466,6 +465,7 @@ theorem toLinearEquiv_quotientEquivOfIsTopCompl (h : IsTopCompl p q) : (quotientEquivOfIsTopCompl p q h : (M ⧸ p) ≃ₗ[R] q) = p.quotientEquivOfIsCompl q h.isCompl := rfl +@[simp] theorem quotientEquivOfIsTopCompl_apply (h : IsTopCompl p q) (x : M ⧸ p) : quotientEquivOfIsTopCompl p q h x = p.quotientEquivOfIsCompl q h.isCompl x := rfl @@ -475,7 +475,6 @@ theorem quotientEquivOfIsTopCompl_symm_apply (h : IsTopCompl p q) (y : q) : (quotientEquivOfIsTopCompl p q h).symm y = p.mkQ y := rfl -@[simp] theorem quotientEquivOfIsTopCompl_apply_mk (h : IsTopCompl p q) (x : M) : quotientEquivOfIsTopCompl p q h (Quotient.mk x) = q.projectionOnto p h.isCompl.symm x := quotientEquivOfIsCompl_apply_mk h.isCompl x @@ -492,7 +491,8 @@ variable {R : Type*} [Ring R] {E F : Type*} {p q : Submodule R E} /-- Given continuous linear maps `φ : p →L[R] F` and `ψ : q →L[R] F` from topological complement -submodules of `E`, the induced continuous linear map `E →L[R] F`. +submodules `p` and `q` of `E`, `ContinuousLinearMap.ofIsCompl` is the induced continuous linear map +`E →L[R] F` over the entire module. This is the continuous version of `LinearMap.ofIsCompl`. -/ noncomputable def ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : E →L[R] F := @@ -508,14 +508,15 @@ theorem toLinearMap_ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q rfl @[simp] +theorem ofIsTopCompl_apply (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) (x : E) : + ofIsTopCompl h φ ψ (x : E) = LinearMap.ofIsCompl h.isCompl φ ψ x := by + rfl + theorem ofIsTopCompl_apply_left (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) (x : p) : - ofIsTopCompl h φ ψ (x : E) = φ x := by - simp [ofIsTopCompl] + ofIsTopCompl h φ ψ (x : E) = φ x := by simp -@[simp] theorem ofIsTopCompl_apply_right (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) (x : q) : - ofIsTopCompl h φ ψ (x : E) = ψ x := by - simp [ofIsTopCompl] + ofIsTopCompl h φ ψ (x : E) = ψ x := by simp theorem ofIsTopCompl_eq (h : IsTopCompl p q) {φ : p →L[R] F} {ψ : q →L[R] F} {χ : E →L[R] F} (hφ : ∀ u : p, φ u = χ u) (hψ : ∀ u : q, ψ u = χ u) : ofIsTopCompl h φ ψ = χ := by From 9c58317676b48166d8b8528e1a209bb2b2c33030 Mon Sep 17 00:00:00 2001 From: sharky564 Date: Fri, 15 May 2026 03:43:20 +1000 Subject: [PATCH 090/210] PR cleanups --- Mathlib/Topology/Algebra/Module/Complement.lean | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Mathlib/Topology/Algebra/Module/Complement.lean b/Mathlib/Topology/Algebra/Module/Complement.lean index 1b6f1c61107ce4..6461adecb717dc 100644 --- a/Mathlib/Topology/Algebra/Module/Complement.lean +++ b/Mathlib/Topology/Algebra/Module/Complement.lean @@ -504,12 +504,12 @@ theorem ofIsTopCompl_eq_add (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L @[simp] theorem toLinearMap_ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : - (ofIsTopCompl h φ ψ : E →ₗ[R] F) = LinearMap.ofIsCompl h.isCompl φ ψ := by + (ofIsTopCompl h φ ψ : E →ₗ[R] F) = LinearMap.ofIsCompl h.isCompl φ ψ := rfl @[simp] theorem ofIsTopCompl_apply (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) (x : E) : - ofIsTopCompl h φ ψ (x : E) = LinearMap.ofIsCompl h.isCompl φ ψ x := by + ofIsTopCompl h φ ψ (x : E) = LinearMap.ofIsCompl h.isCompl φ ψ x := rfl theorem ofIsTopCompl_apply_left (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) (x : p) : @@ -520,18 +520,16 @@ theorem ofIsTopCompl_apply_right (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q theorem ofIsTopCompl_eq (h : IsTopCompl p q) {φ : p →L[R] F} {ψ : q →L[R] F} {χ : E →L[R] F} (hφ : ∀ u : p, φ u = χ u) (hψ : ∀ u : q, ψ u = χ u) : ofIsTopCompl h φ ψ = χ := by - ext x - obtain ⟨_, _, rfl, _⟩ := existsUnique_add_of_isCompl h.isCompl x - simp [hφ, hψ] + ext; simp [LinearMap.ofIsCompl_eq h.isCompl hφ, hψ] @[simp] theorem ofIsTopCompl_zero (h : IsTopCompl p q) : (ofIsTopCompl h 0 0 : E →L[R] F) = 0 := by - ext; simp [ofIsTopCompl] + ext; simp @[simp] theorem ofIsTopCompl_add (h : IsTopCompl p q) (φ₁ φ₂ : p →L[R] F) (ψ₁ ψ₂ : q →L[R] F) : ofIsTopCompl h (φ₁ + φ₂) (ψ₁ + ψ₂) = ofIsTopCompl h φ₁ ψ₁ + ofIsTopCompl h φ₂ ψ₂ := by - ext; simp [ofIsTopCompl, add_add_add_comm] + ext; simp theorem range_ofIsTopCompl (h : IsTopCompl p q) (φ : p →L[R] F) (ψ : q →L[R] F) : LinearMap.range (ofIsTopCompl h φ ψ : E →ₗ[R] F) = φ.range ⊔ ψ.range := by simp From 2bab2783e3e8566f9e0cfa85358281c8478962d8 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 14 May 2026 14:33:27 -0400 Subject: [PATCH 091/210] documentation --- .../Normed/Operator/Perturbation/StrictByFinite.lean | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 8157ec4a527b1f..15dc888d7f3513 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -137,14 +137,23 @@ theorem step2_backward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : I [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_clemb : IsClosedEmbedding (restrict A u)) : IsStrictMap u ∧ IsClosed (range u) := by + -- Fix `S` an algebraic complement of `A` containing `K`. Note that `S` has finite + -- dimension. rcases A.exists_isCompl with ⟨S, A_compl_S⟩ have : FiniteDimensional 𝕜 S := quotientEquivOfIsCompl A S A_compl_S |>.finiteDimensional + -- Because `map u A` is closed by assumption, it follows that `u.range = map u A ⊔ map u S` + -- is closed. have range_u_closed : IsClosed (u.range : Set F) := by rw [isClosedEmbedding_iff, range_restrict] at h_clemb have : u.range = (map u.toLinearMap A ⊔ map u.toLinearMap S) := by rw [← Submodule.map_sup, A_compl_S.sup_eq_top, Submodule.map_top] exact this ▸ Submodule.isClosed_sup_finiteDimensional _ _ h_clemb.2 + -- It remains to show that `u` is strict, which means precisely that the co-restriction + -- `u' : E → u.range` is a quotient map. By step 1, it is enough to show that + -- `restrict A u'` is a closed embedding. This follows from the fact that + -- `restrict A u = u.range.subtype ∘ restrict A u'`, since both + -- `restrict A u` and `u.range.subtype` are closed embeddings. refine ⟨?_, range_u_closed⟩ set u' : E →L[𝕜] u.range := u.rangeRestrict have h_clemb' : IsClosedEmbedding (restrict A u') := by From 544dbb476f6c3f5a9cb6faabd14a2888486712e3 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 14 May 2026 23:20:21 -0400 Subject: [PATCH 092/210] Some progress, but I'm getting tired --- .../Operator/Perturbation/StrictByFinite.lean | 25 ++++++++++++++++--- .../Topology/Algebra/Module/LinearMap.lean | 8 ++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 15dc888d7f3513..5116f5f57de872 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -110,6 +110,7 @@ The statement becomes: `u` is strict with closed range if and only if `Set.restr a closed embedding. -/ +omit [IsTopologicalAddGroup F] [ContinuousSMul 𝕜 F] in theorem step2_forward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_strict : IsStrictMap u) (h_closed : IsClosed (range u)) : IsClosedEmbedding (restrict A u) := by @@ -123,11 +124,14 @@ theorem step2_forward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : Is let u' : E ⧸ u.ker →L[𝕜] F := u.ker.liftQL u le_rfl have eq : restrict A u = u' ∘ restrict A π := by ext x; simp [π, u'] have u'_clemb : IsClosedEmbedding u' := by - -- But strictness of `u` means precisely that `u'` is an embedding, - -- and we assumed that `u` (hence `u'`) has closed range. + -- By assumption, `range u' = range u` is closed. + -- We also assumed that `u` is strict, which precisely means that `u'` is an embedding. -- Hence, we are done. constructor - · have : Injective u' := by simp [u', ← LinearMap.ker_eq_bot, ker_liftQ_eq_bot] + · -- Note: this should be simpler with more API on strict group homs; + -- the issue is that the quotients associated to `LinearMap.ker` and `Setoid.ker` + -- are not defeq... + have : Injective u' := by simp [u', ← LinearMap.ker_eq_bot, ker_liftQ_eq_bot] simpa [isEmbedding_iff_isStrictMap_injective, this, and_true, u.ker.isQuotientMap_mkQL.isStrictMap_iff] · simpa [u', ← LinearMap.coe_range, Submodule.range_liftQ] @@ -230,12 +234,25 @@ section FiniteDimQuotient -- TODO: better name -- TODO: use ∘ or ∘L ? The simp NF is ∘ -public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_quotient +public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_quotient [T1Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 F) [dim_A : FiniteDimensional 𝕜 A] (A_compl : ClosedComplemented A) : (IsStrictMap u ∧ IsClosed (range u)) ↔ (IsStrictMap (A.mkQ ∘ u) ∧ IsClosed (range (A.mkQ ∘ u))) := by obtain ⟨S, A_compl_S⟩ := A_compl.exists_isTopCompl + let Φ : (F ⧸ A) ≃L[𝕜] S := A.quotientEquivOfIsTopCompl S A_compl_S + let i : S →L[𝕜] F := S.subtypeL + have i_clemb : IsClosedEmbedding i := S.isClosedEmbedding_subtypeL A_compl_S.symm.isClosed + let p : F →L[𝕜] F := S.projectionL A A_compl_S.symm + have eq : i ∘ Φ ∘ A.mkQ = p := rfl + simp_rw [Φ.toHomeomorph.isEmbedding.isStrictMap_iff, ← Φ.toHomeomorph.isClosed_image, + i_clemb.isStrictMap_iff, i_clemb.isClosed_iff_image_isClosed, ← range_comp, Φ.coe_toHomeomorph] + -- simp_rw [Φ.toHomeomorph.isEmbedding.isStrictMap_iff, ← Φ.toHomeomorph.isClosed_image, + -- ← range_comp, ← Function.comp_assoc, Φ.coe_toHomeomorph, eq, + -- S.isEmbedding_subtypeL.isStrictMap_iff, + -- S.isClosedEmbedding_subtypeL A_compl_S.symm.isClosed |>.isClosed_iff_image_isClosed, + -- ← range_comp, ← ContinuousLinearMap.coe_comp'] + -- simp sorry end FiniteDimQuotient diff --git a/Mathlib/Topology/Algebra/Module/LinearMap.lean b/Mathlib/Topology/Algebra/Module/LinearMap.lean index 43b4880fa0672f..28435740377aff 100644 --- a/Mathlib/Topology/Algebra/Module/LinearMap.lean +++ b/Mathlib/Topology/Algebra/Module/LinearMap.lean @@ -1256,6 +1256,14 @@ alias coe_subtypeL' := coe_subtypeL theorem subtypeL_apply (p : Submodule R M) (x : p) : p.subtypeL x = x := by simp +theorem isEmbedding_subtype (p : Submodule R M) : IsEmbedding p.subtype := .subtypeVal +theorem isEmbedding_subtypeL (p : Submodule R M) : IsEmbedding p.subtypeL := .subtypeVal + +theorem isClosedEmbedding_subtype (p : Submodule R M) (hp : IsClosed (p : Set M)) : + IsClosedEmbedding p.subtype := .subtypeVal hp +theorem isClosedEmbedding_subtypeL (p : Submodule R M) (hp : IsClosed (p : Set M)) : + IsClosedEmbedding p.subtypeL := .subtypeVal hp + @[deprecated range_subtype (since := "2026-05-06")] theorem range_subtypeL (p : Submodule R M) : (p.subtypeL : p →ₗ[R] M).range = p := Submodule.range_subtype _ From 0c4c1cde0e63b84c4e7b7b173916bb23d6354713 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 14 May 2026 23:23:31 -0400 Subject: [PATCH 093/210] Suffices --- .../Operator/Perturbation/StrictByFinite.lean | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 5116f5f57de872..d4b0e5d4d2b7a5 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -123,19 +123,18 @@ theorem step2_forward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : Is -- is the injection induced by `u`. Thus, it remains to show that `u'` is also a closed embedding. let u' : E ⧸ u.ker →L[𝕜] F := u.ker.liftQL u le_rfl have eq : restrict A u = u' ∘ restrict A π := by ext x; simp [π, u'] - have u'_clemb : IsClosedEmbedding u' := by + suffices u'_clemb : IsClosedEmbedding u' from eq ▸ u'_clemb.comp π_restr_clemb -- By assumption, `range u' = range u` is closed. -- We also assumed that `u` is strict, which precisely means that `u'` is an embedding. -- Hence, we are done. - constructor - · -- Note: this should be simpler with more API on strict group homs; - -- the issue is that the quotients associated to `LinearMap.ker` and `Setoid.ker` - -- are not defeq... - have : Injective u' := by simp [u', ← LinearMap.ker_eq_bot, ker_liftQ_eq_bot] - simpa [isEmbedding_iff_isStrictMap_injective, this, and_true, - u.ker.isQuotientMap_mkQL.isStrictMap_iff] - · simpa [u', ← LinearMap.coe_range, Submodule.range_liftQ] - exact eq ▸ u'_clemb.comp π_restr_clemb + constructor + · -- Note: this should be simpler with more API on strict group homs; + -- the issue is that the quotients associated to `LinearMap.ker` and `Setoid.ker` + -- are not defeq... + have : Injective u' := by simp [u', ← LinearMap.ker_eq_bot, ker_liftQ_eq_bot] + simpa [isEmbedding_iff_isStrictMap_injective, this, and_true, + u.ker.isQuotientMap_mkQL.isStrictMap_iff] + · simpa [u', ← LinearMap.coe_range, Submodule.range_liftQ] theorem step2_backward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) From 1c068aecdef7c911a8bc996df3a88d3e1d902fd3 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 14 May 2026 23:29:54 -0400 Subject: [PATCH 094/210] Cleanup --- .../Operator/Perturbation/StrictByFinite.lean | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index d4b0e5d4d2b7a5..93c724a612bd73 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -140,29 +140,30 @@ theorem step2_backward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : I [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_clemb : IsClosedEmbedding (restrict A u)) : IsStrictMap u ∧ IsClosed (range u) := by - -- Fix `S` an algebraic complement of `A` containing `K`. Note that `S` has finite + -- Fix `S` an algebraic complement of `A` containing `u.ker`. Note that `S` has finite -- dimension. rcases A.exists_isCompl with ⟨S, A_compl_S⟩ have : FiniteDimensional 𝕜 S := quotientEquivOfIsCompl A S A_compl_S |>.finiteDimensional - -- Because `map u A` is closed by assumption, it follows that `u.range = map u A ⊔ map u S` - -- is closed. + -- Because `map u A` is closed and `map u S` is finite dimensional, we know that + -- `u.range = map u A ⊔ map u S` is closed. have range_u_closed : IsClosed (u.range : Set F) := by rw [isClosedEmbedding_iff, range_restrict] at h_clemb have : u.range = (map u.toLinearMap A ⊔ map u.toLinearMap S) := by rw [← Submodule.map_sup, A_compl_S.sup_eq_top, Submodule.map_top] exact this ▸ Submodule.isClosed_sup_finiteDimensional _ _ h_clemb.2 + refine ⟨?_, range_u_closed⟩ -- It remains to show that `u` is strict, which means precisely that the co-restriction -- `u' : E → u.range` is a quotient map. By step 1, it is enough to show that - -- `restrict A u'` is a closed embedding. This follows from the fact that - -- `restrict A u = u.range.subtype ∘ restrict A u'`, since both - -- `restrict A u` and `u.range.subtype` are closed embeddings. - refine ⟨?_, range_u_closed⟩ + -- `restrict A u'` is a closed embedding. set u' : E →L[𝕜] u.range := u.rangeRestrict - have h_clemb' : IsClosedEmbedding (restrict A u') := by - rw [← range_u_closed.isClosedEmbedding_subtypeVal.of_comp_iff] - exact h_clemb - exact step1_backward u' A A_closed (by simpa [u']) (by simp [u']) h_clemb' + change IsQuotientMap u' + suffices IsClosedEmbedding (restrict A u') from + step1_backward u' A A_closed (by simpa [u']) (by simp [u']) this + -- This follows from the equality `restrict A u = u.range.subtype ∘ restrict A u'`, + -- and the fact that both `restrict A u` and `u.range.subtype` are closed embeddings. + rw [← range_u_closed.isClosedEmbedding_subtypeVal.of_comp_iff] + exact h_clemb theorem step2 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) : From 6098574d43bc885272706fa11887ad2b3035b555 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 14 May 2026 23:47:22 -0400 Subject: [PATCH 095/210] Docstring --- .../Operator/Perturbation/StrictByFinite.lean | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 93c724a612bd73..ff5388aaa6eb32 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -11,6 +11,30 @@ public import Mathlib.Topology.Algebra.Module.FiniteDimension /-! # Strict linear maps with closed range are closed under finite-rank perturbation + +Fix `𝕜` a complete nontrivially normed field, and `E`, `F` two topological vector spaces +over `𝕜`. This file contains various results expressing that the set of continuous +linear maps `u : E →L[𝕜] F` which are **strict** and have **closed range** is +"stable under finite-rank perturbations". + +More precisely, we prove the following statements: +* `ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict`: given a closed + subspace `A` of `E` of finite codimension, we have that `u` is strict with closed range + if and only if `u.domRestrict A` is strict with closed range. +* `ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict`: if `u, v : E →L[𝕜] F` + differ by a finite rank continuous linear map, then `u` is strict with closed range if and only + if `v` is strict with closed range. +* `ContinuousLinearMap.isStrictMap_isClosed_range_iff_quotient`: given a *complemented* + finite dimensional subspace `B` of `F`, we have that `u` is strict with closed range + if and only if `B.mkQL ∘L u` is strict with closed range. + +These three results show up crucially when developping the theory of Fredholm operators +between topological vector spaces. Note that none of the results here use the Hahn-Banach +theorem, so there is no significant restriction on the field. + +## References + +* [N. Bourbaki, *Théories Spectrales*, Chapitre III, § 3, n° 1][bourbaki2023] -/ open Topology Set Submodule Function @@ -176,6 +200,11 @@ theorem step2 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed ( We now deduce from the two previous step the full strength of the theorem. -/ +/-- Consider `u : E →L[𝕜] F` and `A` a closed subspace of `E` of finite codimension. +We have that `u` is strict with closed range if and only if `u.domRestrict A` is strict with +closed range. + +This is [N. Bourbaki, *Théories Spectrales*, Chapitre III, § 3, n° 1, Prop. 1][bourbaki2023]. -/ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] : @@ -217,6 +246,10 @@ end FiniteCodimSubspace section FiniteRank -- TODO: state in terms of "equality modulo finite rank" relation +/-- If `u, v : E →L[𝕜] F` differ by a finite rank continuous linear map, then `u` is strict with +closed range if and only if `v` is strict with closed range. + +This is [N. Bourbaki, *Théories Spectrales*, Chapitre III, § 3, n° 1, Cor. 1][bourbaki2023]. -/ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_finiteDimensional [T1Space F] (u v : E →L[𝕜] F) (h_finite_rank : FiniteDimensional 𝕜 (u - v).range) : (IsStrictMap u ∧ IsClosed (range u)) ↔ (IsStrictMap v ∧ IsClosed (range v)) := by @@ -234,6 +267,10 @@ section FiniteDimQuotient -- TODO: better name -- TODO: use ∘ or ∘L ? The simp NF is ∘ +/-- Consider `u : E →L[𝕜] F` and `B` a *complemented* finite dimensional subspace `F`. We have +that `u` is strict with closed range if and only if `B.mkQL ∘L u` is strict with closed range. + +This is [N. Bourbaki, *Théories Spectrales*, Chapitre III, § 3, n° 1, Cor. 2][bourbaki2023]. -/ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_quotient [T1Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 F) [dim_A : FiniteDimensional 𝕜 A] (A_compl : ClosedComplemented A) : From 8506b4475be93973ff9fb2c70aecd94605a846e5 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 14 May 2026 23:48:30 -0400 Subject: [PATCH 096/210] ++ --- .../Analysis/Normed/Operator/Perturbation/StrictByFinite.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index ff5388aaa6eb32..b4c60db8d39e99 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -243,6 +243,10 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict (u : end FiniteCodimSubspace +/-! +## Consequences +-/ + section FiniteRank -- TODO: state in terms of "equality modulo finite rank" relation From 94265b13845ab7290f89d955bdb5216a9094f610 Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Fri, 15 May 2026 05:49:15 +0200 Subject: [PATCH 097/210] Update Mathlib/Topology/LocalAtTarget.lean --- Mathlib/Topology/LocalAtTarget.lean | 2 -- 1 file changed, 2 deletions(-) diff --git a/Mathlib/Topology/LocalAtTarget.lean b/Mathlib/Topology/LocalAtTarget.lean index e35a8a97667c72..adba5129b27f71 100644 --- a/Mathlib/Topology/LocalAtTarget.lean +++ b/Mathlib/Topology/LocalAtTarget.lean @@ -21,8 +21,6 @@ We show that the following properties of continuous maps are local at the target - `Topology.IsOpenEmbedding` - `Topology.IsClosedEmbedding` - `GeneralizingMap` -- `IsProperMap` -- `IsOpenQuotientMap` We show that the following properties of continuous maps are local at the source: - `IsOpenMap` From faa51bfb04e4c74186d68502e4a029722e08ea35 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 15 May 2026 10:59:30 -0400 Subject: [PATCH 098/210] Nice calc proof ! --- .../Operator/Perturbation/StrictByFinite.lean | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index b4c60db8d39e99..a68ab4e84efc82 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -241,6 +241,17 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict (u : simp [step2 v B B_closed v_ker, isClosedEmbedding_iff, range_restrict v, isEmbedding_iff_isStrictMap_injective, v_restr_inj] +-- TODO: state in terms of "equality modulo finite rank" relation +/-- If `u, v : E →L[𝕜] F` agree on a closed subspace `A` of `E` with finite codimension, +then `u` is strict with closed range if and only if `v` is strict with closed range. -/ +public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_eqOn [T1Space F] + (u v : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) + [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_eqOn : EqOn u v A) : + (IsStrictMap u ∧ IsClosed (range u)) ↔ (IsStrictMap v ∧ IsClosed (range v)) := by + simp_rw [u.isStrictMap_isClosed_range_iff_restrict A, + v.isStrictMap_isClosed_range_iff_restrict A, + ← range_restrict, restrict_eq_restrict_iff.mpr h_eqOn] + end FiniteCodimSubspace /-! @@ -250,6 +261,7 @@ end FiniteCodimSubspace section FiniteRank -- TODO: state in terms of "equality modulo finite rank" relation +-- TODO: unify with statement above /-- If `u, v : E →L[𝕜] F` differ by a finite rank continuous linear map, then `u` is strict with closed range if and only if `v` is strict with closed range. @@ -258,12 +270,10 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_finiteDimen (u v : E →L[𝕜] F) (h_finite_rank : FiniteDimensional 𝕜 (u - v).range) : (IsStrictMap u ∧ IsClosed (range u)) ↔ (IsStrictMap v ∧ IsClosed (range v)) := by let A := (u - v).ker - have hA : IsClosed (A : Set E) := (u - v).isClosed_ker + have A_closed : IsClosed (A : Set E) := (u - v).isClosed_ker have : FiniteDimensional 𝕜 (E ⧸ A) := (u - v).toLinearMap.quotKerEquivRange.symm.finiteDimensional have eqOn_A : EqOn u v A := fun _ ↦ by simp [A, sub_eq_zero] - simp_rw [u.isStrictMap_isClosed_range_iff_restrict A hA, - v.isStrictMap_isClosed_range_iff_restrict A hA, - ← range_restrict, restrict_eq_restrict_iff.mpr eqOn_A] + exact ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_eqOn u v A A_closed eqOn_A end FiniteRank @@ -286,14 +296,19 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_quotient [T1Sp have i_clemb : IsClosedEmbedding i := S.isClosedEmbedding_subtypeL A_compl_S.symm.isClosed let p : F →L[𝕜] F := S.projectionL A A_compl_S.symm have eq : i ∘ Φ ∘ A.mkQ = p := rfl - simp_rw [Φ.toHomeomorph.isEmbedding.isStrictMap_iff, ← Φ.toHomeomorph.isClosed_image, - i_clemb.isStrictMap_iff, i_clemb.isClosed_iff_image_isClosed, ← range_comp, Φ.coe_toHomeomorph] - -- simp_rw [Φ.toHomeomorph.isEmbedding.isStrictMap_iff, ← Φ.toHomeomorph.isClosed_image, - -- ← range_comp, ← Function.comp_assoc, Φ.coe_toHomeomorph, eq, - -- S.isEmbedding_subtypeL.isStrictMap_iff, - -- S.isClosedEmbedding_subtypeL A_compl_S.symm.isClosed |>.isClosed_iff_image_isClosed, - -- ← range_comp, ← ContinuousLinearMap.coe_comp'] - -- simp - sorry + have : FiniteDimensional 𝕜 (u - p ∘L u).range := by + suffices (u - p ∘L u).range ≤ A from finiteDimensional_of_le this + rintro - ⟨x, rfl⟩ + exact sub_projection_mem _ (u x) + calc IsStrictMap u ∧ IsClosed (range u) + _ ↔ (IsStrictMap (p ∘ u) ∧ IsClosed (range (p ∘ u))) := + ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_finiteDimensional _ _ this + _ ↔ (IsStrictMap (i ∘ Φ ∘ A.mkQ ∘ u) ∧ IsClosed (range (i ∘ Φ ∘ A.mkQ ∘ u))) := by + simp_rw [← eq, Function.comp_assoc] + _ ↔ (IsStrictMap (Φ ∘ A.mkQ ∘ u) ∧ IsClosed (range (Φ ∘ A.mkQ ∘ u))) := by + rw [i_clemb.isStrictMap_iff, i_clemb.isClosed_iff_image_isClosed, ← range_comp] + _ ↔ (IsStrictMap (A.mkQ ∘ u) ∧ IsClosed (range (A.mkQ ∘ u))) := by + rw [Φ.toHomeomorph.isEmbedding.isStrictMap_iff, ← Φ.toHomeomorph.isClosed_image, + ← range_comp, Φ.coe_toHomeomorph] end FiniteDimQuotient From 9c5f404f7c08f477947dc2da71532bd1c05a90a5 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 15 May 2026 11:18:57 -0400 Subject: [PATCH 099/210] ++ --- .../Normed/Operator/Perturbation/StrictByFinite.lean | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index a68ab4e84efc82..46e44bfd4950fa 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -122,6 +122,14 @@ theorem step1_backward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : I h_range] replace uS_compl_uA : IsTopCompl (map u.toLinearMap S) (map u.toLinearMap A) := uS_compl_uA.symm.isTopCompl_of_isClosed_of_finiteDimensional uA_closed |>.symm + set Φ : (S × A) ≃L[𝕜] E := prodEquivOfIsTopCompl S A S_compl_A + set Ψ : (map u.toLinearMap S × map u.toLinearMap A) ≃L[𝕜] F := + prodEquivOfIsTopCompl _ _ uS_compl_uA + set u₁ : A →L[𝕜] map u.toLinearMap A := u.restrict (fun _ ↦ mem_map_of_mem) + --have eq : u = Ψ ∘ ((u.restrict)) + -- suffices IsQuotientMap (Ψ.symm ∘ u ∘ Φ) by + -- simpa [Function.comp_assoc] using Ψ.toHomeomorph.isQuotientMap.comp + -- (this.comp Φ.symm.toHomeomorph.isQuotientMap) sorry /-! From 9fd9e5d025f1b5849cec81c9455d394e8763bcbd Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 15 May 2026 11:56:36 -0400 Subject: [PATCH 100/210] Sorry free !! --- .../Operator/Perturbation/StrictByFinite.lean | 49 ++++++++++++------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 46e44bfd4950fa..2f70b42efcb8de 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -103,7 +103,7 @@ theorem step1_foward (A : Submodule 𝕜 E) (K : Submodule 𝕜 E) (A_closed : I Note the hypothesis `h_ker` is implied `h_clemb`, but since this is a private theorem we just write the most convenient statement to prove and use. -/ -theorem step1_backward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) +theorem step1_backward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) (h_clemb : IsClosedEmbedding (restrict A u)) : IsQuotientMap u := by @@ -125,12 +125,22 @@ theorem step1_backward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : I set Φ : (S × A) ≃L[𝕜] E := prodEquivOfIsTopCompl S A S_compl_A set Ψ : (map u.toLinearMap S × map u.toLinearMap A) ≃L[𝕜] F := prodEquivOfIsTopCompl _ _ uS_compl_uA - set u₁ : A →L[𝕜] map u.toLinearMap A := u.restrict (fun _ ↦ mem_map_of_mem) - --have eq : u = Ψ ∘ ((u.restrict)) - -- suffices IsQuotientMap (Ψ.symm ∘ u ∘ Φ) by - -- simpa [Function.comp_assoc] using Ψ.toHomeomorph.isQuotientMap.comp - -- (this.comp Φ.symm.toHomeomorph.isQuotientMap) - sorry + set u₁ : S →L[𝕜] map u.toLinearMap S := u.restrict (fun _ ↦ mem_map_of_mem) + set u₂ : A →L[𝕜] map u.toLinearMap A := u.restrict (fun _ ↦ mem_map_of_mem) + have u₁_surj : Surjective u₁ := surjective_mapsTo_image_restrict _ _ + have u₂_surj : Surjective u₂ := surjective_mapsTo_image_restrict _ _ + have eq : u = Ψ ∘ (u₁.prodMap u₂) ∘ Φ.symm := by + ext x + simp [Φ, Ψ, u₁, u₂, ← map_add, projectionL_add_projectionL_eq_self] + suffices IsQuotientMap (Prod.map u₁ u₂) from eq ▸ + (Ψ.toHomeomorph.isQuotientMap.comp this |>.comp Φ.symm.toHomeomorph.isQuotientMap) + refine IsOpenQuotientMap.prodMap ?_ ?_ |>.isQuotientMap <;> + apply AddMonoidHom.isOpenQuotientMap_of_isQuotientMap ?_ + · refine ContinuousLinearMap.isQuotientMap_of_finiteDimensional u₁ + (u₁.range_eq_top_of_surjective u₁_surj) + · simp_rw [isQuotientMap_iff_isStrictMap_surjective, u₂_surj, and_true, + (map u.toLinearMap A).isEmbedding_subtype.isStrictMap_iff] + exact h_clemb.isStrictMap /-! ### Step 2 @@ -143,9 +153,10 @@ a closed embedding. -/ omit [IsTopologicalAddGroup F] [ContinuousSMul 𝕜 F] in -theorem step2_forward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) - [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_strict : IsStrictMap u) - (h_closed : IsClosed (range u)) : IsClosedEmbedding (restrict A u) := by +theorem step2_forward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) + (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] + (h_ker : Disjoint u.ker A) (h_strict : IsStrictMap u) (h_closed : IsClosed (range u)) : + IsClosedEmbedding (restrict A u) := by -- Denote by `π : E → E ⧸ u.ker` the quotient map. Since `u.ker` is disjoint from `A`, we know -- from step 1 that `restrict A π` is a closed embedding. let π : E →L[𝕜] E ⧸ u.ker := u.ker.mkQL @@ -168,9 +179,9 @@ theorem step2_forward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : Is u.ker.isQuotientMap_mkQL.isStrictMap_iff] · simpa [u', ← LinearMap.coe_range, Submodule.range_liftQ] -theorem step2_backward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) - [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) - (h_clemb : IsClosedEmbedding (restrict A u)) : +theorem step2_backward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) + (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] + (h_ker : Disjoint u.ker A) (h_clemb : IsClosedEmbedding (restrict A u)) : IsStrictMap u ∧ IsClosed (range u) := by -- Fix `S` an algebraic complement of `A` containing `u.ker`. Note that `S` has finite -- dimension. @@ -197,7 +208,7 @@ theorem step2_backward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : I rw [← range_u_closed.isClosedEmbedding_subtypeVal.of_comp_iff] exact h_clemb -theorem step2 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) +theorem step2 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) : (IsStrictMap u ∧ IsClosed (range u)) ↔ IsClosedEmbedding (restrict A u) := ⟨fun H ↦ step2_forward u A A_closed h_ker H.1 H.2, step2_backward u A A_closed h_ker⟩ @@ -213,11 +224,11 @@ We have that `u` is strict with closed range if and only if `u.domRestrict A` is closed range. This is [N. Bourbaki, *Théories Spectrales*, Chapitre III, § 3, n° 1, Prop. 1][bourbaki2023]. -/ -public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict (u : E →L[𝕜] F) - (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) +public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Space F] + (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] : (IsStrictMap u ∧ IsClosed (range u)) ↔ - (IsStrictMap (restrict A u) ∧ IsClosed (u '' A)) := by + (IsStrictMap (Set.restrict A u) ∧ IsClosed (u '' A)) := by set N : Submodule 𝕜 E := A ⊓ u.ker set π : E →L[𝕜] E ⧸ N := N.mkQL set v : E ⧸ N →L[𝕜] F := N.liftQL u inf_le_right @@ -236,11 +247,11 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict (u : let φ : (N.mkQL ⁻¹' B) ≃ₜ A := .setCongr congr(SetLike.coe $comap_B) exact N.isOpenQuotientMap_mkQL.restrictPreimage B |>.comp φ.symm.isOpenQuotientMap - have v_comp_π'_eq_u : restrict B v ∘ π' = restrict A u := rfl + have v_comp_π'_eq_u : Set.restrict B v ∘ π' = Set.restrict A u := rfl have v_ker : Disjoint v.ker B := by simp [disjoint_iff, v, B, toLinearMap_liftQL, ker_liftQ, map_inf_eq_map_inf_comap, comap_map_mkQ, N, inf_comm] - have v_restr_inj : Injective (restrict B v) := + have v_restr_inj : Injective (Set.restrict B v) := injOn_iff_injective.mp <| LinearMap.injOn_of_disjoint_ker subset_rfl v_ker.symm have range_eq : range v = range u := range_quot_lift _ have image_eq : v '' B = u '' A := by simp [B, ← v_comp_π_eq_u, π, ← image_comp] From 772544585230f7d7ce7eb443ae9daccdc965ac8c Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 15 May 2026 11:57:38 -0400 Subject: [PATCH 101/210] long line --- .../Normed/Operator/Perturbation/StrictByFinite.lean | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 2f70b42efcb8de..80ebffd0b67414 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -103,8 +103,9 @@ theorem step1_foward (A : Submodule 𝕜 E) (K : Submodule 𝕜 E) (A_closed : I Note the hypothesis `h_ker` is implied `h_clemb`, but since this is a private theorem we just write the most convenient statement to prove and use. -/ -theorem step1_backward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) - [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) +theorem step1_backward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) + (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] + (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) (h_clemb : IsClosedEmbedding (restrict A u)) : IsQuotientMap u := by rcases h_ker.exists_isCompl with ⟨S, ker_le_S, S_compl_A⟩ From 89fa2d1608b206151f046d52dd9a0bb1573b511d Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 15 May 2026 12:15:27 -0400 Subject: [PATCH 102/210] Doc step1_backward --- .../Operator/Perturbation/StrictByFinite.lean | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 80ebffd0b67414..2ab62855125901 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -108,21 +108,34 @@ theorem step1_backward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) (h_clemb : IsClosedEmbedding (restrict A u)) : IsQuotientMap u := by + -- Fix `S` an algebraic complement of `A` containing `u.ker`. It has finite dimension. rcases h_ker.exists_isCompl with ⟨S, ker_le_S, S_compl_A⟩ + have : FiniteDimensional 𝕜 S := + quotientEquivOfIsCompl A S S_compl_A.symm |>.finiteDimensional + -- Because `A` is closed with finite codimension, `S` is in fact a topological complement of `A`. replace S_compl_A : IsTopCompl S A := S_compl_A.symm.isTopCompl_of_finiteDimensional_quotient A_closed |>.symm - have : FiniteDimensional 𝕜 S := - quotientEquivOfIsCompl A S S_compl_A.isCompl.symm |>.finiteDimensional + -- By assumption, `map u A` is closed. have uA_closed : IsClosed (map u.toLinearMap A : Set F) := by simpa [← range_restrict] using h_clemb.isClosed_range + -- Because `u` is assumed surjective and `S ⊔ A = ⊤`, we have `map u S ⊔ map u A = ⊤`. + -- Furthermore, because the kernel of `u` is fully contained in `S`, we can show that + -- `map u S ⊓ map u A = ⊥`, so that `map u S` and `map u A` are in fact algebraic complements + -- of each other. have uS_compl_uA : IsCompl (map u.toLinearMap S) (map u.toLinearMap A) := by constructor · rw [disjoint_iff, inf_comm, map_inf_eq_map_inf_comap, comap_map_eq, sup_eq_left.mpr ker_le_S, S_compl_A.isCompl.symm.inf_eq_bot, Submodule.map_bot] · rw [codisjoint_iff, ← Submodule.map_sup, S_compl_A.isCompl.sup_eq_top, Submodule.map_top, h_range] + -- Since `map u S` has finite dimension, `map u A` has finite codimension. But we also know that + -- `map u A` is closed so, once again, `map u S` and `map u A` are in fact *topological* + -- complements of each other. replace uS_compl_uA : IsTopCompl (map u.toLinearMap S) (map u.toLinearMap A) := uS_compl_uA.symm.isTopCompl_of_isClosed_of_finiteDimensional uA_closed |>.symm + -- Thus, we have decomposed both the comain and the codomain into topopological complements. + -- Using the corresponding isomorphisms `(S × A) ≃L[𝕜] E` and `(map u S × map u A) ≃L[𝕜] F`, + -- we have to show that the map `u₁.prodMap u₂ : S × A → map u S × map u A` is a quotient map. set Φ : (S × A) ≃L[𝕜] E := prodEquivOfIsTopCompl S A S_compl_A set Ψ : (map u.toLinearMap S × map u.toLinearMap A) ≃L[𝕜] F := prodEquivOfIsTopCompl _ _ uS_compl_uA @@ -135,10 +148,15 @@ theorem step1_backward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) simp [Φ, Ψ, u₁, u₂, ← map_add, projectionL_add_projectionL_eq_self] suffices IsQuotientMap (Prod.map u₁ u₂) from eq ▸ (Ψ.toHomeomorph.isQuotientMap.comp this |>.comp Φ.symm.toHomeomorph.isQuotientMap) + -- Since linear quotient maps are automatically open, and since the product of two open quotient + -- maps is a quotient map, this reduces to showing that both `u₁` and `u₂` are quotient maps. refine IsOpenQuotientMap.prodMap ?_ ?_ |>.isQuotientMap <;> apply AddMonoidHom.isOpenQuotientMap_of_isQuotientMap ?_ + -- `u₁` is a quotient map because it is a surjective linear map between finite dimensional spaces. · refine ContinuousLinearMap.isQuotientMap_of_finiteDimensional u₁ (u₁.range_eq_top_of_surjective u₁_surj) + -- `u₂` is strict because `(map u A).subtype ∘ u₂ = u.restrict A` is an embedding (hence strict) + -- by assumptions. Since `u₂` is surjective, it is a quotient map, and we are done. · simp_rw [isQuotientMap_iff_isStrictMap_surjective, u₂_surj, and_true, (map u.toLinearMap A).isEmbedding_subtype.isStrictMap_iff] exact h_clemb.isStrictMap From 8485d05d712f3515ebf9e71b73f9d2d5713afaed Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 15 May 2026 12:41:41 -0400 Subject: [PATCH 103/210] Finish documenting proof! --- .../Operator/Perturbation/StrictByFinite.lean | 49 ++++++++++++++----- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 2ab62855125901..8ed362cbb28617 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -248,18 +248,45 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Sp [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] : (IsStrictMap u ∧ IsClosed (range u)) ↔ (IsStrictMap (Set.restrict A u) ∧ IsClosed (u '' A)) := by + -- To reduce to step 2, we quotient by `N := A ⊓ u.ker`. Denoting by `π : E → E ⧸ N` + -- the (automatically open) quotient map, `u` factors as `v ∘ π` with `v : E ⧸ N → F`. set N : Submodule 𝕜 E := A ⊓ u.ker set π : E →L[𝕜] E ⧸ N := N.mkQL set v : E ⧸ N →L[𝕜] F := N.liftQL u inf_le_right have π_quot : IsOpenQuotientMap π := N.isOpenQuotientMap_mkQL have v_comp_π_eq_u : v ∘ π = u := rfl + -- We also consider the submodule `B := map π A` of `E ⧸ N`. It has finite codimension and, + -- by construction, it is disjoint from the kernel of `v`. set B : Submodule 𝕜 (E ⧸ N) := map N.mkQ A + have codim_B : FiniteDimensional 𝕜 ((E ⧸ N) ⧸ B) := + quotientQuotientEquivQuotient N A inf_le_left |>.symm.finiteDimensional + have v_ker : Disjoint v.ker B := by + simp [disjoint_iff, v, B, toLinearMap_liftQL, ker_liftQ, + map_inf_eq_map_inf_comap, comap_map_mkQ, N, inf_comm] + have v_restr_inj : Injective (Set.restrict B v) := + injOn_iff_injective.mp <| LinearMap.injOn_of_disjoint_ker subset_rfl v_ker.symm + -- Because `A` contains `N`, we have `A = comap π B`. In particular, `B` is closed. have comap_B : comap π.toLinearMap B = A := by simp [B, N, π] have A_mapsTo_B : MapsTo π A B := fun _ ↦ by simp [← comap_B] have B_closed : IsClosed (B : Set <| E ⧸ N) := by rwa [← π_quot.isQuotientMap.isClosed_preimage, ← π.coe_coe, ← comap_coe, comap_B] - have codim_B : FiniteDimensional 𝕜 ((E ⧸ N) ⧸ B) := - quotientQuotientEquivQuotient N A inf_le_left |>.symm.finiteDimensional + -- Thus, we can apply step 2 to `v`: we get that `v` is strict with closed range if + -- and only if `v.restrict B` is strict with closed range. + have step2_output : (IsStrictMap v ∧ IsClosed (range v)) ↔ + (IsStrictMap (Set.restrict B v) ∧ IsClosed (v '' B)) := by + simp [step2 v B B_closed v_ker, isClosedEmbedding_iff, ← range_restrict, + isEmbedding_iff_isStrictMap_injective, v_restr_inj] + -- Now, we wish to reduce our statement about `u` and `u.restrict A` + -- to what we know about `v` and `v.restrict B`. + -- First, it is clear that `range u = range v` and `u '' A = v '' B`. + have range_eq : range v = range u := range_quot_lift _ + have image_eq : v '' B = u '' A := by simp [B, ← v_comp_π_eq_u, π, ← image_comp] + -- Furthermore, since `π` is a quotient map and `u = v ∘ π`, we have that `u` is strict + -- if and only if `v` is strict. + have strict_iff : IsStrictMap u ↔ IsStrictMap v := by + rw [← v_comp_π_eq_u, ← π_quot.isQuotientMap.isStrictMap_iff] + -- Now, recall the equality `A = comap π B`; it ensures that the restriction + -- `π' : A → B` of the open quotient map `π` is *still* an (open quotient map). set π' : A →L[𝕜] B := ⟨π.restrict A_mapsTo_B, π.continuous.restrict A_mapsTo_B⟩ have π'_quot : IsOpenQuotientMap π' := by @@ -267,17 +294,13 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Sp exact N.isOpenQuotientMap_mkQL.restrictPreimage B |>.comp φ.symm.isOpenQuotientMap have v_comp_π'_eq_u : Set.restrict B v ∘ π' = Set.restrict A u := rfl - have v_ker : Disjoint v.ker B := by - simp [disjoint_iff, v, B, toLinearMap_liftQL, ker_liftQ, - map_inf_eq_map_inf_comap, comap_map_mkQ, N, inf_comm] - have v_restr_inj : Injective (Set.restrict B v) := - injOn_iff_injective.mp <| LinearMap.injOn_of_disjoint_ker subset_rfl v_ker.symm - have range_eq : range v = range u := range_quot_lift _ - have image_eq : v '' B = u '' A := by simp [B, ← v_comp_π_eq_u, π, ← image_comp] - rw [← range_eq, ← image_eq, ← v_comp_π'_eq_u, ← v_comp_π_eq_u, - ← π_quot.isQuotientMap.isStrictMap_iff, ← π'_quot.isQuotientMap.isStrictMap_iff] - simp [step2 v B B_closed v_ker, isClosedEmbedding_iff, range_restrict v, - isEmbedding_iff_isStrictMap_injective, v_restr_inj] + -- Because `v.restrict B ∘ π' = u.restrict A`, it follows that `u.restrict A` + -- is strict if and only if `v.restrict B` is strict. + have strict_iff_restrict : IsStrictMap (Set.restrict A u) ↔ IsStrictMap (Set.restrict B v) := by + rw [← v_comp_π'_eq_u, ← π'_quot.isQuotientMap.isStrictMap_iff] + -- Thus, we are done! + rw [strict_iff, strict_iff_restrict, ← range_eq, ← image_eq] + exact step2_output -- TODO: state in terms of "equality modulo finite rank" relation /-- If `u, v : E →L[𝕜] F` agree on a closed subspace `A` of `E` with finite codimension, From 7e0b75cb4c87c61e29f5ef0afac4e87587f182eb Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 15 May 2026 16:52:58 -0400 Subject: [PATCH 104/210] I'm lost honestly --- Mathlib/Algebra/Module/Submodule/Ker.lean | 1 + Mathlib/Algebra/Module/Submodule/Map.lean | 22 +++++++++++++++++-- Mathlib/Algebra/Module/Submodule/Range.lean | 13 +++++++++++ .../Topology/Algebra/Module/LinearMap.lean | 10 ++++----- 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/Mathlib/Algebra/Module/Submodule/Ker.lean b/Mathlib/Algebra/Module/Submodule/Ker.lean index 1ffa229f7c78c5..19fd2a1f0e1245 100644 --- a/Mathlib/Algebra/Module/Submodule/Ker.lean +++ b/Mathlib/Algebra/Module/Submodule/Ker.lean @@ -114,6 +114,7 @@ theorem ker_eq_bot_of_inverse {τ₂₁ : R₂ →+* R} [RingHomInvPair τ₁₂ theorem le_ker_iff_map [RingHomSurjective τ₁₂] {f : M →ₛₗ[τ₁₂] M₂} {p : Submodule R M} : p ≤ ker f ↔ map f p = ⊥ := by rw [ker, eq_bot_iff, map_le_iff_le_comap] +@[simp] theorem ker_codRestrict {τ₂₁ : R₂ →+* R} (p : Submodule R M) (f : M₂ →ₛₗ[τ₂₁] M) (hf) : ker (codRestrict p f hf) = ker f := by rw [ker, comap_codRestrict, Submodule.map_bot]; rfl diff --git a/Mathlib/Algebra/Module/Submodule/Map.lean b/Mathlib/Algebra/Module/Submodule/Map.lean index a7720044777535..8851d75a9236d4 100644 --- a/Mathlib/Algebra/Module/Submodule/Map.lean +++ b/Mathlib/Algebra/Module/Submodule/Map.lean @@ -665,13 +665,31 @@ variable [Semiring R₂] [AddCommMonoid M₂] [Module R₂ M₂] {σ₂₁ : R open Submodule theorem map_codRestrict [RingHomSurjective σ₂₁] (p : Submodule R M) (f : M₂ →ₛₗ[σ₂₁] M) (h p') : - Submodule.map (codRestrict p f h) p' = comap p.subtype (p'.map f) := + map (codRestrict p f h) p' = comap p.subtype (p'.map f) := Submodule.ext fun ⟨x, hx⟩ => by simp [Subtype.ext_iff] theorem comap_codRestrict (p : Submodule R M) (f : M₂ →ₛₗ[σ₂₁] M) (hf p') : - Submodule.comap (codRestrict p f hf) p' = Submodule.comap f (map p.subtype p') := + comap (codRestrict p f hf) p' = comap f (map p.subtype p') := Submodule.ext fun x => ⟨fun h => ⟨⟨_, hf x⟩, h, rfl⟩, by rintro ⟨⟨_, _⟩, h, ⟨⟩⟩; exact h⟩ +theorem map_domRestrict [RingHomSurjective σ₂₁] (p : Submodule R₂ M₂) (f : M₂ →ₛₗ[σ₂₁] M) (p') : + map (domRestrict f p) p' = map f (map p.subtype p') := + map_comp p.subtype f p' + +theorem comap_domRestrict (p : Submodule R₂ M₂) (f : M₂ →ₛₗ[σ₂₁] M) (p') : + comap (domRestrict f p) p' = comap p.subtype (comap f p') := + comap_comp p.subtype f p' + +theorem map_restrict [RingHomSurjective σ₂₁] {p : Submodule R₂ M₂} {q : Submodule R M} + {f : M₂ →ₛₗ[σ₂₁] M} (h : ∀ x ∈ p, f x ∈ q) (p') : + map (f.restrict h) p' = comap q.subtype (map f (map p.subtype p')) := by + rw [restrict_eq_codRestrict_domRestrict, map_codRestrict, map_domRestrict] + +theorem comap_restrict [RingHomSurjective σ₂₁] {p : Submodule R₂ M₂} {q : Submodule R M} + {f : M₂ →ₛₗ[σ₂₁] M} (h : ∀ x ∈ p, f x ∈ q) (p') : + comap (f.restrict h) p' = comap p.subtype (comap f (map q.subtype p')) := by + rw [restrict_eq_codRestrict_domRestrict, comap_codRestrict, comap_domRestrict] + end LinearMap /-! ### Linear equivalences -/ diff --git a/Mathlib/Algebra/Module/Submodule/Range.lean b/Mathlib/Algebra/Module/Submodule/Range.lean index 515b791cdbe4e6..e1d45f5e4625ad 100644 --- a/Mathlib/Algebra/Module/Submodule/Range.lean +++ b/Mathlib/Algebra/Module/Submodule/Range.lean @@ -450,6 +450,19 @@ theorem surjective_rangeRestrict : Surjective f.rangeRestrict := by end rangeRestrict +section restrict + +open Submodule + +variable [RingHomSurjective τ₁₂] (f : M →ₛₗ[τ₁₂] M₂) {p : Submodule R M} {q : Submodule R₂ M₂} + +@[simp] +theorem range_restrict (h : ∀ x ∈ p, f x ∈ q) : + range (f.restrict h) = comap q.subtype (map f p) := by + rw [← Submodule.map_top, map_restrict, Submodule.map_top, p.range_subtype] + +end restrict + end Semiring end LinearMap diff --git a/Mathlib/Topology/Algebra/Module/LinearMap.lean b/Mathlib/Topology/Algebra/Module/LinearMap.lean index 0a787aced787b4..2624a41b896161 100644 --- a/Mathlib/Topology/Algebra/Module/LinearMap.lean +++ b/Mathlib/Topology/Algebra/Module/LinearMap.lean @@ -1298,10 +1298,9 @@ theorem coe_codRestrict_apply (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R (f.codRestrict p h x : M₂) = f x := rfl -@[simp] theorem ker_codRestrict (f : M₁ →SL[σ₁₂] M₂) (p : Submodule R₂ M₂) (h : ∀ x, f x ∈ p) : ker (f.codRestrict p h : M₁ →ₛₗ[σ₁₂] p) = ker (f : M₁ →ₛₗ[σ₁₂] M₂) := - (f : M₁ →ₛₗ[σ₁₂] M₂).ker_codRestrict p h + f.toLinearMap.ker_codRestrict p h @[simp] theorem domRestrict_comp_codRestrict (g : M₂ →SL[σ₂₃] M₃) (f : M₁ →SL[σ₁₂] M₂) @@ -1313,11 +1312,12 @@ theorem domRestrict_comp_codRestrict (g : M₂ →SL[σ₂₃] M₃) (f : M₁ abbrev rangeRestrict [RingHomSurjective σ₁₂] (f : M₁ →SL[σ₁₂] M₂) := f.codRestrict (LinearMap.range (f : M₁ →ₛₗ[σ₁₂] M₂)) (LinearMap.mem_range_self _) +theorem toLinearMap_rangeRestrict [RingHomSurjective σ₁₂] (f : M₁ →SL[σ₁₂] M₂) : + f.rangeRestrict.toLinearMap = f.toLinearMap.rangeRestrict := by simp + @[simp] theorem coe_rangeRestrict [RingHomSurjective σ₁₂] (f : M₁ →SL[σ₁₂] M₂) : - (f.rangeRestrict : M₁ →ₛₗ[σ₁₂] LinearMap.range (f : M₁ →ₛₗ[σ₁₂] M₂)) = - (f : M₁ →ₛₗ[σ₁₂] M₂).rangeRestrict := - rfl + (f.rangeRestrict : M₁ → f.range) = Set.rangeFactorization f := rfl /-- Restrict codomain of a continuous linear map. -/ def restrict (f : M₁ →SL[σ₁₂] M₂) {p : Submodule R₁ M₁} {q : Submodule R₂ M₂} From 1739c5afe4788d701f0e4a08ca787c5eaddf1ab7 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 15 May 2026 18:14:43 -0400 Subject: [PATCH 105/210] fix --- Mathlib/Algebra/Module/Submodule/Range.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Algebra/Module/Submodule/Range.lean b/Mathlib/Algebra/Module/Submodule/Range.lean index e1d45f5e4625ad..cfd5a18a782438 100644 --- a/Mathlib/Algebra/Module/Submodule/Range.lean +++ b/Mathlib/Algebra/Module/Submodule/Range.lean @@ -443,7 +443,7 @@ variable [RingHomSurjective τ₁₂] (f : M →ₛₗ[τ₁₂] M₂) theorem surjective_rangeRestrict : Surjective f.rangeRestrict := by rw [← range_eq_top, range_rangeRestrict] -@[simp] theorem ker_rangeRestrict : ker f.rangeRestrict = ker f := LinearMap.ker_codRestrict _ _ _ +theorem ker_rangeRestrict : ker f.rangeRestrict = ker f := LinearMap.ker_codRestrict _ _ _ @[simp] theorem injective_rangeRestrict_iff : Injective f.rangeRestrict ↔ Injective f := Set.injective_codRestrict _ From 346a59e8e16519107d96ab70dbd7a9c0612076d6 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 15 May 2026 23:04:43 -0400 Subject: [PATCH 106/210] Cleanup statements a bit --- .../Operator/Perturbation/StrictByFinite.lean | 117 +++++++++--------- 1 file changed, 61 insertions(+), 56 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 8ed362cbb28617..f7bb578f42ce54 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -5,6 +5,7 @@ Authors: Anatole Dedecker -/ module +public import Mathlib.RingTheory.Finiteness.Cofinite public import Mathlib.Topology.Maps.Strict.Basic public import Mathlib.Topology.LocalAtTarget public import Mathlib.Topology.Algebra.Module.FiniteDimension @@ -37,7 +38,7 @@ theorem, so there is no significant restriction on the field. * [N. Bourbaki, *Théories Spectrales*, Chapitre III, § 3, n° 1][bourbaki2023] -/ -open Topology Set Submodule Function +open Topology Set Submodule Function ContinuousLinearMap variable {𝕜} [NontriviallyNormedField 𝕜] [CompleteSpace 𝕜] @@ -54,7 +55,7 @@ section FiniteCodimSubspace Let `u : E →L[𝕜] F` be a continuous linear map, and `A` a finite codimension closed subspace of `E`. We want to show that `u` is strict with closed range if and only if -`Set.restrict A u` is strict with closed range. +`u.domRestrict A` is strict with closed range. We do the proof in three steps. -/ @@ -66,20 +67,20 @@ We prove the theorem under the assumptions that - `u` is surjective - `u.ker` is disjoint from `A` (i.e. `u` is injective on `A`) -The statement becomes: `u` is a quotient map if and only if `Set.restrict A u` is +The statement becomes: `u` is a quotient map if and only if `u.domRestrict A` is a closed embedding. -/ /-- The forward direction of step 1 in the proof of `ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict`, which you should use instead. -Note that we only prove it for `u = K.mkQ`, because it is easier and precisely what we will need +Note that we only prove it for `u = K.mkQL`, because it is easier and precisely what we will need in step 2. -/ theorem step1_foward (A : Submodule 𝕜 E) (K : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (K_disj_A : Disjoint K A) : - IsClosedEmbedding (restrict A K.mkQ) := by + IsClosedEmbedding (K.mkQL.domRestrict A) := by constructor - · -- We show that `restrict A K.mkQ` is an embedding by exhibiting a continuous left inverse. + · -- We show that `K.mkQL.domRestrict A` is an embedding by exhibiting a continuous left inverse. -- Fix `S` an algebraic complement of `A` containing `K`. rcases K_disj_A.exists_isCompl with ⟨S, K_le_S, S_compl_A⟩ -- Because `A` is closed with finite codimension, `S` is in fact a topological complement @@ -91,11 +92,11 @@ theorem step1_foward (A : Submodule 𝕜 E) (K : Submodule 𝕜 E) (A_closed : I let s : E ⧸ K →L[𝕜] A := K.liftQL (A.projectionOntoL S S_compl_A.symm) (by simpa) have leftInv : LeftInverse s (restrict A K.mkQ) := fun x ↦ by simp [s] refine .of_leftInverse leftInv s.continuous (by fun_prop) - · -- The subspace `K.mkQ ⁻¹' K.mkQ '' A` contains the closed and finite codimension subspace `A`, - -- hence it is closed. By definition of the quotient topology, this shows that - -- `restrict A K.mkQ` has closed range. - rw [← K.isQuotientMap_mkQ.isClosed_preimage, range_restrict, ← Submodule.map_coe, - ← Submodule.comap_coe K.mkQ] + · -- The subspace `K.mkQL ⁻¹' K.mkQL '' A` contains the closed and finite codimension subspace + -- `A`, hence it is closed. By definition of the quotient topology, this shows that + -- `K.mkQL.domRestrict A` has closed range. + rw [← K.isQuotientMap_mkQ.isClosed_preimage, ContinuousLinearMap.coe_domRestrict, + range_restrict, ← ContinuousLinearMap.coe_coe, ← map_coe, ← comap_coe K.mkQ] exact isClosed_mono_of_finiteDimensional_quotient A_closed (le_comap_map _ A) /-- The backward direction of step 1 in the proof of @@ -106,7 +107,7 @@ we just write the most convenient statement to prove and use. -/ theorem step1_backward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) - (h_clemb : IsClosedEmbedding (restrict A u)) : + (h_clemb : IsClosedEmbedding (u.domRestrict A)) : IsQuotientMap u := by -- Fix `S` an algebraic complement of `A` containing `u.ker`. It has finite dimension. rcases h_ker.exists_isCompl with ⟨S, ker_le_S, S_compl_A⟩ @@ -174,17 +175,17 @@ a closed embedding. omit [IsTopologicalAddGroup F] [ContinuousSMul 𝕜 F] in theorem step2_forward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] - (h_ker : Disjoint u.ker A) (h_strict : IsStrictMap u) (h_closed : IsClosed (range u)) : - IsClosedEmbedding (restrict A u) := by + (h_ker : Disjoint u.ker A) (h_strict : IsStrictMap u) (h_closed : IsClosed (u.range : Set F)) : + IsClosedEmbedding (u.domRestrict A) := by -- Denote by `π : E → E ⧸ u.ker` the quotient map. Since `u.ker` is disjoint from `A`, we know - -- from step 1 that `restrict A π` is a closed embedding. + -- from step 1 that `π.domRestrict A` is a closed embedding. let π : E →L[𝕜] E ⧸ u.ker := u.ker.mkQL - have π_restr_clemb : IsClosedEmbedding (restrict A π) := + have π_restr_clemb : IsClosedEmbedding (π.domRestrict A) := step1_foward A u.ker A_closed h_ker - -- But we can factor `restrict A u` as `u' ∘ restrict A π`, where `u' : E ⧸ u.ker → F` + -- But we can factor `u.domRestrict A` as `u' ∘ π.domRestrict A`, where `u' : E ⧸ u.ker → F` -- is the injection induced by `u`. Thus, it remains to show that `u'` is also a closed embedding. let u' : E ⧸ u.ker →L[𝕜] F := u.ker.liftQL u le_rfl - have eq : restrict A u = u' ∘ restrict A π := by ext x; simp [π, u'] + have eq : u.domRestrict A = u' ∘L π.domRestrict A := by ext x; simp [π, u'] suffices u'_clemb : IsClosedEmbedding u' from eq ▸ u'_clemb.comp π_restr_clemb -- By assumption, `range u' = range u` is closed. -- We also assumed that `u` is strict, which precisely means that `u'` is an embedding. @@ -200,8 +201,8 @@ theorem step2_forward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) theorem step2_backward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] - (h_ker : Disjoint u.ker A) (h_clemb : IsClosedEmbedding (restrict A u)) : - IsStrictMap u ∧ IsClosed (range u) := by + (h_ker : Disjoint u.ker A) (h_clemb : IsClosedEmbedding (u.domRestrict A)) : + IsStrictMap u ∧ IsClosed (u.range : Set F) := by -- Fix `S` an algebraic complement of `A` containing `u.ker`. Note that `S` has finite -- dimension. rcases A.exists_isCompl with ⟨S, A_compl_S⟩ @@ -210,27 +211,28 @@ theorem step2_backward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) -- Because `map u A` is closed and `map u S` is finite dimensional, we know that -- `u.range = map u A ⊔ map u S` is closed. have range_u_closed : IsClosed (u.range : Set F) := by - rw [isClosedEmbedding_iff, range_restrict] at h_clemb + rw [isClosedEmbedding_iff, ContinuousLinearMap.coe_domRestrict, range_restrict] at h_clemb have : u.range = (map u.toLinearMap A ⊔ map u.toLinearMap S) := by rw [← Submodule.map_sup, A_compl_S.sup_eq_top, Submodule.map_top] exact this ▸ Submodule.isClosed_sup_finiteDimensional _ _ h_clemb.2 refine ⟨?_, range_u_closed⟩ -- It remains to show that `u` is strict, which means precisely that the co-restriction - -- `u' : E → u.range` is a quotient map. By step 1, it is enough to show that - -- `restrict A u'` is a closed embedding. + -- `u' : E → u.range` is a quotient map. set u' : E →L[𝕜] u.range := u.rangeRestrict - change IsQuotientMap u' - suffices IsClosedEmbedding (restrict A u') from + suffices IsQuotientMap u' from isStrictMap_iff_isQuotientMap_rangeFactorization _ |>.mpr this + -- By step 1, it is enough to show that `u'.domRestrict A` is a closed embedding. + suffices IsClosedEmbedding (u'.domRestrict A) from step1_backward u' A A_closed (by simpa [u']) (by simp [u']) this - -- This follows from the equality `restrict A u = u.range.subtype ∘ restrict A u'`, - -- and the fact that both `restrict A u` and `u.range.subtype` are closed embeddings. + -- This follows from the equality `u.domRestrict A = u.range.subtype ∘L u'.domRestrict A`, + -- and the fact that both `u.domRestrict A` and `u.range.subtype` are closed embeddings. rw [← range_u_closed.isClosedEmbedding_subtypeVal.of_comp_iff] exact h_clemb theorem step2 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) : - (IsStrictMap u ∧ IsClosed (range u)) ↔ IsClosedEmbedding (restrict A u) := - ⟨fun H ↦ step2_forward u A A_closed h_ker H.1 H.2, step2_backward u A A_closed h_ker⟩ + (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ IsClosedEmbedding (u.domRestrict A) := + ⟨fun H ↦ step2_forward u A A_closed h_ker H.1 H.2, + step2_backward u A A_closed h_ker⟩ /-! ### Step 3 @@ -246,15 +248,15 @@ This is [N. Bourbaki, *Théories Spectrales*, Chapitre III, § 3, n° 1, Prop. 1 public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] : - (IsStrictMap u ∧ IsClosed (range u)) ↔ - (IsStrictMap (Set.restrict A u) ∧ IsClosed (u '' A)) := by + (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ + (IsStrictMap (u.domRestrict A) ∧ IsClosed (map u.toLinearMap A : Set F)) := by -- To reduce to step 2, we quotient by `N := A ⊓ u.ker`. Denoting by `π : E → E ⧸ N` -- the (automatically open) quotient map, `u` factors as `v ∘ π` with `v : E ⧸ N → F`. set N : Submodule 𝕜 E := A ⊓ u.ker set π : E →L[𝕜] E ⧸ N := N.mkQL set v : E ⧸ N →L[𝕜] F := N.liftQL u inf_le_right have π_quot : IsOpenQuotientMap π := N.isOpenQuotientMap_mkQL - have v_comp_π_eq_u : v ∘ π = u := rfl + have v_comp_π_eq_u : v ∘L π = u := rfl -- We also consider the submodule `B := map π A` of `E ⧸ N`. It has finite codimension and, -- by construction, it is disjoint from the kernel of `v`. set B : Submodule 𝕜 (E ⧸ N) := map N.mkQ A @@ -271,33 +273,33 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Sp have B_closed : IsClosed (B : Set <| E ⧸ N) := by rwa [← π_quot.isQuotientMap.isClosed_preimage, ← π.coe_coe, ← comap_coe, comap_B] -- Thus, we can apply step 2 to `v`: we get that `v` is strict with closed range if - -- and only if `v.restrict B` is strict with closed range. - have step2_output : (IsStrictMap v ∧ IsClosed (range v)) ↔ - (IsStrictMap (Set.restrict B v) ∧ IsClosed (v '' B)) := by - simp [step2 v B B_closed v_ker, isClosedEmbedding_iff, ← range_restrict, - isEmbedding_iff_isStrictMap_injective, v_restr_inj] - -- Now, we wish to reduce our statement about `u` and `u.restrict A` - -- to what we know about `v` and `v.restrict B`. - -- First, it is clear that `range u = range v` and `u '' A = v '' B`. - have range_eq : range v = range u := range_quot_lift _ - have image_eq : v '' B = u '' A := by simp [B, ← v_comp_π_eq_u, π, ← image_comp] + -- and only if `v.domRestrict B` is strict with closed range. + have step2_output : (IsStrictMap v ∧ IsClosed (v.range : Set F)) ↔ + (IsStrictMap (v.domRestrict B) ∧ IsClosed (map v.toLinearMap B : Set F)) := by + simp [step2 v B B_closed v_ker, isClosedEmbedding_iff, ContinuousLinearMap.coe_domRestrict, + ← range_restrict, isEmbedding_iff_isStrictMap_injective, v_restr_inj] + -- Now, we wish to reduce our statement about `u` and `u.domRestrict A` + -- to what we know about `v` and `v.domRestrict B`. + -- First, it is clear that `range u = range v` and `map u A = map v B`. + have range_eq : v.range = u.range := range_liftQ _ _ _ + have image_eq : map v.toLinearMap B = map u.toLinearMap A := by + simp [B, ← v_comp_π_eq_u, π, ← map_comp] -- Furthermore, since `π` is a quotient map and `u = v ∘ π`, we have that `u` is strict -- if and only if `v` is strict. have strict_iff : IsStrictMap u ↔ IsStrictMap v := by - rw [← v_comp_π_eq_u, ← π_quot.isQuotientMap.isStrictMap_iff] + rw [← v_comp_π_eq_u, ContinuousLinearMap.coe_comp', ← π_quot.isQuotientMap.isStrictMap_iff] -- Now, recall the equality `A = comap π B`; it ensures that the restriction -- `π' : A → B` of the open quotient map `π` is *still* an (open quotient map). - set π' : A →L[𝕜] B := - ⟨π.restrict A_mapsTo_B, π.continuous.restrict A_mapsTo_B⟩ + set π' : A →L[𝕜] B := π.restrict A_mapsTo_B have π'_quot : IsOpenQuotientMap π' := by let φ : (N.mkQL ⁻¹' B) ≃ₜ A := .setCongr congr(SetLike.coe $comap_B) exact N.isOpenQuotientMap_mkQL.restrictPreimage B |>.comp φ.symm.isOpenQuotientMap - have v_comp_π'_eq_u : Set.restrict B v ∘ π' = Set.restrict A u := rfl - -- Because `v.restrict B ∘ π' = u.restrict A`, it follows that `u.restrict A` - -- is strict if and only if `v.restrict B` is strict. - have strict_iff_restrict : IsStrictMap (Set.restrict A u) ↔ IsStrictMap (Set.restrict B v) := by - rw [← v_comp_π'_eq_u, ← π'_quot.isQuotientMap.isStrictMap_iff] + have v_comp_π'_eq_u : v.domRestrict B ∘L π' = u.domRestrict A := rfl + -- Because `v.domRestrict B ∘ π' = u.domRestrict A`, it follows that `u.domRestrict A` + -- is strict if and only if `v.domRestrict B` is strict. + have strict_iff_restrict : IsStrictMap (u.domRestrict A) ↔ IsStrictMap (v.domRestrict B) := by + rw [← v_comp_π'_eq_u, ContinuousLinearMap.coe_comp', ← π'_quot.isQuotientMap.isStrictMap_iff] -- Thus, we are done! rw [strict_iff, strict_iff_restrict, ← range_eq, ← image_eq] exact step2_output @@ -308,10 +310,12 @@ then `u` is strict with closed range if and only if `v` is strict with closed ra public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_eqOn [T1Space F] (u v : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_eqOn : EqOn u v A) : - (IsStrictMap u ∧ IsClosed (range u)) ↔ (IsStrictMap v ∧ IsClosed (range v)) := by + (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ + (IsStrictMap v ∧ IsClosed (v.range : Set F)) := by simp_rw [u.isStrictMap_isClosed_range_iff_restrict A, - v.isStrictMap_isClosed_range_iff_restrict A, - ← range_restrict, restrict_eq_restrict_iff.mpr h_eqOn] + v.isStrictMap_isClosed_range_iff_restrict A, ← LinearMap.range_domRestrict, + LinearMap.coe_range, LinearMap.coe_domRestrict, ContinuousLinearMap.coe_domRestrict, + ContinuousLinearMap.coe_coe, restrict_eq_restrict_iff.mpr h_eqOn] end FiniteCodimSubspace @@ -329,7 +333,8 @@ closed range if and only if `v` is strict with closed range. This is [N. Bourbaki, *Théories Spectrales*, Chapitre III, § 3, n° 1, Cor. 1][bourbaki2023]. -/ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_finiteDimensional [T1Space F] (u v : E →L[𝕜] F) (h_finite_rank : FiniteDimensional 𝕜 (u - v).range) : - (IsStrictMap u ∧ IsClosed (range u)) ↔ (IsStrictMap v ∧ IsClosed (range v)) := by + (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ + (IsStrictMap v ∧ IsClosed (v.range : Set F)) := by let A := (u - v).ker have A_closed : IsClosed (A : Set E) := (u - v).isClosed_ker have : FiniteDimensional 𝕜 (E ⧸ A) := (u - v).toLinearMap.quotKerEquivRange.symm.finiteDimensional @@ -349,8 +354,8 @@ This is [N. Bourbaki, *Théories Spectrales*, Chapitre III, § 3, n° 1, Cor. 2] public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_quotient [T1Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 F) [dim_A : FiniteDimensional 𝕜 A] (A_compl : ClosedComplemented A) : - (IsStrictMap u ∧ IsClosed (range u)) ↔ - (IsStrictMap (A.mkQ ∘ u) ∧ IsClosed (range (A.mkQ ∘ u))) := by + (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ + (IsStrictMap (A.mkQL ∘L u) ∧ IsClosed ((A.mkQL ∘L u).range : Set (F ⧸ A))) := by obtain ⟨S, A_compl_S⟩ := A_compl.exists_isTopCompl let Φ : (F ⧸ A) ≃L[𝕜] S := A.quotientEquivOfIsTopCompl S A_compl_S let i : S →L[𝕜] F := S.subtypeL From d0cf5008c8b9f4b801dbc803dc2de6d242dcc267 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 19 May 2026 12:32:43 +0200 Subject: [PATCH 107/210] Significantly simplified the proof (at least morally) --- .../Operator/Perturbation/StrictByFinite.lean | 122 +++++++++++++++--- 1 file changed, 107 insertions(+), 15 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index f7bb578f42ce54..2b7f0e7b95b605 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -57,7 +57,7 @@ Let `u : E →L[𝕜] F` be a continuous linear map, and `A` a finite codimensio subspace of `E`. We want to show that `u` is strict with closed range if and only if `u.domRestrict A` is strict with closed range. -We do the proof in three steps. +We do the proof in four steps. -/ /-! @@ -74,9 +74,9 @@ a closed embedding. /-- The forward direction of step 1 in the proof of `ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict`, which you should use instead. -Note that we only prove it for `u = K.mkQL`, because it is easier and precisely what we will need -in step 2. -/ -theorem step1_foward (A : Submodule 𝕜 E) (K : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) +We prove it first for `u = K.mkQL`, because we have no analog of `Submodule.liftQL` for arbitrary +linear quotient maps; when this is solved, this should be merged with `step1_forward` below. -/ +theorem step1_foward' (A : Submodule 𝕜 E) (K : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (K_disj_A : Disjoint K A) : IsClosedEmbedding (K.mkQL.domRestrict A) := by constructor @@ -99,6 +99,26 @@ theorem step1_foward (A : Submodule 𝕜 E) (K : Submodule 𝕜 E) (A_closed : I range_restrict, ← ContinuousLinearMap.coe_coe, ← map_coe, ← comap_coe K.mkQ] exact isClosed_mono_of_finiteDimensional_quotient A_closed (le_comap_map _ A) +omit [IsTopologicalAddGroup F] [ContinuousSMul 𝕜 F] in +/-- The forward direction of step 1 in the proof of +`ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict`, which you should use instead. -/ +theorem step1_foward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) + (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] + (h_ker : Disjoint u.ker A) (h_quot : IsQuotientMap u) : + IsClosedEmbedding (u.domRestrict A) := by + -- Because `u` is a quotient linear map, we can identify it with "the" quotient map + -- `E → E ⧸ u.ker`, for which we have proven the result above. + -- TODO: there should be API + set Φ : (E ⧸ u.ker) ≃L[𝕜] F := + { toLinearEquiv := u.toLinearMap.quotKerEquivOfSurjective h_quot.surjective + continuous_toFun := continuous_quot_lift _ h_quot.continuous + continuous_invFun := h_quot.continuous_iff.mpr <| u.ker.continuous_mkQ.congr fun x ↦ by + simp [← ContinuousLinearMap.coe_coe] } + -- TODO: there should be API + have Φ_clemb : IsClosedEmbedding Φ := Φ.toHomeomorph.isClosedEmbedding + have eq : u.domRestrict A = Φ ∘L u.ker.mkQL.domRestrict A := rfl + simpa [eq, Φ_clemb.of_comp_iff] using step1_foward' A u.ker A_closed h_ker + /-- The backward direction of step 1 in the proof of `ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict`, which you should use instead. @@ -162,9 +182,56 @@ theorem step1_backward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (map u.toLinearMap A).isEmbedding_subtype.isStrictMap_iff] exact h_clemb.isStrictMap +theorem step1 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) + (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] + (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) : + IsQuotientMap u ↔ IsClosedEmbedding (u.domRestrict A) := + ⟨step1_foward u A A_closed h_ker, step1_backward u A A_closed h_ker h_range⟩ + /-! ### Step 2 +We prove the theorem under the assumptions that +- `u` has closed range +- `u.ker` is disjoint from `A` (i.e. `u` is injective on `A`) + +The statement becomes: `u` is strict if and only if `Set.restrict A u` is a closed embedding. +-/ + +theorem step2 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) + (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] + (h_ker : Disjoint u.ker A) (h_range : IsClosed (u.range : Set F)) : + IsStrictMap u ↔ IsClosedEmbedding (u.domRestrict A) := by + -- Let `F' := u.range` and `i : F' →L[𝕜] F` be the inclusion map. By assumption, + -- `i` is a closed embedding. + set F' : Submodule 𝕜 F := u.range + set i : F' →L[𝕜] F := F'.subtypeL + have i_clemb : IsClosedEmbedding i := F'.isClosedEmbedding_subtypeL h_range + -- Furthermore, `u` factors as `i ∘ u'` with `u' : E →L[𝕜] F'` surjective, + -- and we clearly have `u.domRestrict A = i ∘ u'.domRestrict A` as well. + set u' : E →L[𝕜] F' := u.rangeRestrict + have range_u' : u'.range = ⊤ := u.range_rangeRestrict + have u'_surj : Surjective u' := u.surjective_rangeRestrict + have eq1 : u = i ∘L u' := rfl + have eq2 : u.domRestrict A = i ∘L (u'.domRestrict A) := rfl + -- Note that we still have that `u'.ker = u.ker` is disjoint from `A`. + have ker_u' : u'.ker = u.ker := u.ker_rangeRestrict + -- Thus we can apply step 1 to `u'`, and we get that `u'` is strict if and only if + -- `u'.domRestrict A` is a closed embedding. + have step1_output : IsQuotientMap u' ↔ IsClosedEmbedding (u'.domRestrict A) := + step1 u' A A_closed (ker_u' ▸ h_ker) range_u' + -- On the other hand: + -- * since `i` is an embedding, `u = i ∘ u'` is strict if and only if `u'` is strict + -- (hence a quotient map, by surjectivity); + -- * since `i` is a closed embedding, `u.domRestrict A = i ∘ u'.domRestrict A` is a closed + -- embedding if and only if `u'.domRestrict A` is a closed embedding. + -- Hence, we have proven our statement. + simp_rw [eq2, eq1, ContinuousLinearMap.coe_comp', i_clemb.of_comp_iff, ← i_clemb.isStrictMap_iff, + ← step1_output, isQuotientMap_iff_isStrictMap_surjective, u'_surj, and_true] + +/-! +### Step 3 + We prove the theorem under the assumption that `u.ker` is disjoint from `A` (i.e. `u` is injective on `A`). @@ -172,8 +239,33 @@ The statement becomes: `u` is strict with closed range if and only if `Set.restr a closed embedding. -/ +theorem step3_new [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) + [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) : + (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ IsClosedEmbedding (u.domRestrict A) := by + -- It suffices to show that, if `u.domRestrict A` is a closed embedding, then the range of `u` + -- is closed. Indeed, if this is the case, both sides of the equivalence imply that `u` has + -- closed range, so we can invoke step 2 to prove each direction. + suffices IsClosedEmbedding (u.domRestrict A) → IsClosed (u.range : Set F) by + rw [← iff_self_and] at this + rw [this, and_congr_left_iff] + exact step2 u A A_closed h_ker + -- Thus, assume that `u.domRestrict A` is a closed embedding. In particular, `map u A` is closed. + intro h_clemb + rw [isClosedEmbedding_iff, ← ContinuousLinearMap.coe_coe, ← LinearMap.coe_range, + ContinuousLinearMap.toLinearMap_domRestrict, LinearMap.range_domRestrict] at h_clemb + -- Fix `S` an algebraic complement of `A` containing `u.ker`. Note that `S` has finite + -- dimension. + rcases A.exists_isCompl with ⟨S, A_compl_S⟩ + have : FiniteDimensional 𝕜 S := + quotientEquivOfIsCompl A S A_compl_S |>.finiteDimensional + -- Because `map u A` is closed and `map u S` is finite dimensional, we get that + -- `u.range = map u A ⊔ map u S` is closed. + have : u.range = (map u.toLinearMap A ⊔ map u.toLinearMap S) := by + rw [← Submodule.map_sup, A_compl_S.sup_eq_top, Submodule.map_top] + exact this ▸ Submodule.isClosed_sup_finiteDimensional _ _ h_clemb.2 + omit [IsTopologicalAddGroup F] [ContinuousSMul 𝕜 F] in -theorem step2_forward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) +theorem step3_forward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_strict : IsStrictMap u) (h_closed : IsClosed (u.range : Set F)) : IsClosedEmbedding (u.domRestrict A) := by @@ -181,7 +273,7 @@ theorem step2_forward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) -- from step 1 that `π.domRestrict A` is a closed embedding. let π : E →L[𝕜] E ⧸ u.ker := u.ker.mkQL have π_restr_clemb : IsClosedEmbedding (π.domRestrict A) := - step1_foward A u.ker A_closed h_ker + step1_foward' A u.ker A_closed h_ker -- But we can factor `u.domRestrict A` as `u' ∘ π.domRestrict A`, where `u' : E ⧸ u.ker → F` -- is the injection induced by `u`. Thus, it remains to show that `u'` is also a closed embedding. let u' : E ⧸ u.ker →L[𝕜] F := u.ker.liftQL u le_rfl @@ -199,7 +291,7 @@ theorem step2_forward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) u.ker.isQuotientMap_mkQL.isStrictMap_iff] · simpa [u', ← LinearMap.coe_range, Submodule.range_liftQ] -theorem step2_backward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) +theorem step3_backward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_clemb : IsClosedEmbedding (u.domRestrict A)) : IsStrictMap u ∧ IsClosed (u.range : Set F) := by @@ -228,14 +320,14 @@ theorem step2_backward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) rw [← range_u_closed.isClosedEmbedding_subtypeVal.of_comp_iff] exact h_clemb -theorem step2 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) +theorem step3 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) : (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ IsClosedEmbedding (u.domRestrict A) := - ⟨fun H ↦ step2_forward u A A_closed h_ker H.1 H.2, - step2_backward u A A_closed h_ker⟩ + ⟨fun H ↦ step3_forward u A A_closed h_ker H.1 H.2, + step3_backward u A A_closed h_ker⟩ /-! -### Step 3 +### Step 4 We now deduce from the two previous step the full strength of the theorem. -/ @@ -272,11 +364,11 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Sp have A_mapsTo_B : MapsTo π A B := fun _ ↦ by simp [← comap_B] have B_closed : IsClosed (B : Set <| E ⧸ N) := by rwa [← π_quot.isQuotientMap.isClosed_preimage, ← π.coe_coe, ← comap_coe, comap_B] - -- Thus, we can apply step 2 to `v`: we get that `v` is strict with closed range if + -- Thus, we can apply step 3 to `v`: we get that `v` is strict with closed range if -- and only if `v.domRestrict B` is strict with closed range. - have step2_output : (IsStrictMap v ∧ IsClosed (v.range : Set F)) ↔ + have step3_output : (IsStrictMap v ∧ IsClosed (v.range : Set F)) ↔ (IsStrictMap (v.domRestrict B) ∧ IsClosed (map v.toLinearMap B : Set F)) := by - simp [step2 v B B_closed v_ker, isClosedEmbedding_iff, ContinuousLinearMap.coe_domRestrict, + simp [step3 v B B_closed v_ker, isClosedEmbedding_iff, ContinuousLinearMap.coe_domRestrict, ← range_restrict, isEmbedding_iff_isStrictMap_injective, v_restr_inj] -- Now, we wish to reduce our statement about `u` and `u.domRestrict A` -- to what we know about `v` and `v.domRestrict B`. @@ -302,7 +394,7 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Sp rw [← v_comp_π'_eq_u, ContinuousLinearMap.coe_comp', ← π'_quot.isQuotientMap.isStrictMap_iff] -- Thus, we are done! rw [strict_iff, strict_iff_restrict, ← range_eq, ← image_eq] - exact step2_output + exact step3_output -- TODO: state in terms of "equality modulo finite rank" relation /-- If `u, v : E →L[𝕜] F` agree on a closed subspace `A` of `E` with finite codimension, From db244c5cab8337007bd0158ecef4351700f35ec8 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 19 May 2026 12:33:10 +0200 Subject: [PATCH 108/210] Cleanup --- .../Operator/Perturbation/StrictByFinite.lean | 64 +------------------ 1 file changed, 1 insertion(+), 63 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 2b7f0e7b95b605..578ec2ad2e486c 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -239,7 +239,7 @@ The statement becomes: `u` is strict with closed range if and only if `Set.restr a closed embedding. -/ -theorem step3_new [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) +theorem step3 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) : (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ IsClosedEmbedding (u.domRestrict A) := by -- It suffices to show that, if `u.domRestrict A` is a closed embedding, then the range of `u` @@ -264,68 +264,6 @@ theorem step3_new [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_clo rw [← Submodule.map_sup, A_compl_S.sup_eq_top, Submodule.map_top] exact this ▸ Submodule.isClosed_sup_finiteDimensional _ _ h_clemb.2 -omit [IsTopologicalAddGroup F] [ContinuousSMul 𝕜 F] in -theorem step3_forward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) - (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] - (h_ker : Disjoint u.ker A) (h_strict : IsStrictMap u) (h_closed : IsClosed (u.range : Set F)) : - IsClosedEmbedding (u.domRestrict A) := by - -- Denote by `π : E → E ⧸ u.ker` the quotient map. Since `u.ker` is disjoint from `A`, we know - -- from step 1 that `π.domRestrict A` is a closed embedding. - let π : E →L[𝕜] E ⧸ u.ker := u.ker.mkQL - have π_restr_clemb : IsClosedEmbedding (π.domRestrict A) := - step1_foward' A u.ker A_closed h_ker - -- But we can factor `u.domRestrict A` as `u' ∘ π.domRestrict A`, where `u' : E ⧸ u.ker → F` - -- is the injection induced by `u`. Thus, it remains to show that `u'` is also a closed embedding. - let u' : E ⧸ u.ker →L[𝕜] F := u.ker.liftQL u le_rfl - have eq : u.domRestrict A = u' ∘L π.domRestrict A := by ext x; simp [π, u'] - suffices u'_clemb : IsClosedEmbedding u' from eq ▸ u'_clemb.comp π_restr_clemb - -- By assumption, `range u' = range u` is closed. - -- We also assumed that `u` is strict, which precisely means that `u'` is an embedding. - -- Hence, we are done. - constructor - · -- Note: this should be simpler with more API on strict group homs; - -- the issue is that the quotients associated to `LinearMap.ker` and `Setoid.ker` - -- are not defeq... - have : Injective u' := by simp [u', ← LinearMap.ker_eq_bot, ker_liftQ_eq_bot] - simpa [isEmbedding_iff_isStrictMap_injective, this, and_true, - u.ker.isQuotientMap_mkQL.isStrictMap_iff] - · simpa [u', ← LinearMap.coe_range, Submodule.range_liftQ] - -theorem step3_backward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) - (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] - (h_ker : Disjoint u.ker A) (h_clemb : IsClosedEmbedding (u.domRestrict A)) : - IsStrictMap u ∧ IsClosed (u.range : Set F) := by - -- Fix `S` an algebraic complement of `A` containing `u.ker`. Note that `S` has finite - -- dimension. - rcases A.exists_isCompl with ⟨S, A_compl_S⟩ - have : FiniteDimensional 𝕜 S := - quotientEquivOfIsCompl A S A_compl_S |>.finiteDimensional - -- Because `map u A` is closed and `map u S` is finite dimensional, we know that - -- `u.range = map u A ⊔ map u S` is closed. - have range_u_closed : IsClosed (u.range : Set F) := by - rw [isClosedEmbedding_iff, ContinuousLinearMap.coe_domRestrict, range_restrict] at h_clemb - have : u.range = (map u.toLinearMap A ⊔ map u.toLinearMap S) := by - rw [← Submodule.map_sup, A_compl_S.sup_eq_top, Submodule.map_top] - exact this ▸ Submodule.isClosed_sup_finiteDimensional _ _ h_clemb.2 - refine ⟨?_, range_u_closed⟩ - -- It remains to show that `u` is strict, which means precisely that the co-restriction - -- `u' : E → u.range` is a quotient map. - set u' : E →L[𝕜] u.range := u.rangeRestrict - suffices IsQuotientMap u' from isStrictMap_iff_isQuotientMap_rangeFactorization _ |>.mpr this - -- By step 1, it is enough to show that `u'.domRestrict A` is a closed embedding. - suffices IsClosedEmbedding (u'.domRestrict A) from - step1_backward u' A A_closed (by simpa [u']) (by simp [u']) this - -- This follows from the equality `u.domRestrict A = u.range.subtype ∘L u'.domRestrict A`, - -- and the fact that both `u.domRestrict A` and `u.range.subtype` are closed embeddings. - rw [← range_u_closed.isClosedEmbedding_subtypeVal.of_comp_iff] - exact h_clemb - -theorem step3 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) - [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) : - (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ IsClosedEmbedding (u.domRestrict A) := - ⟨fun H ↦ step3_forward u A A_closed h_ker H.1 H.2, - step3_backward u A A_closed h_ker⟩ - /-! ### Step 4 From 022f53116c4410c1a38cbfc280c71f9d9eacde78 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 19 May 2026 12:56:38 +0200 Subject: [PATCH 109/210] ++ --- .../Analysis/Normed/Operator/Perturbation/StrictByFinite.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 578ec2ad2e486c..aae74ee0a74085 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -222,7 +222,7 @@ theorem step2 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) step1 u' A A_closed (ker_u' ▸ h_ker) range_u' -- On the other hand: -- * since `i` is an embedding, `u = i ∘ u'` is strict if and only if `u'` is strict - -- (hence a quotient map, by surjectivity); + -- (i.e a quotient map, by surjectivity); -- * since `i` is a closed embedding, `u.domRestrict A = i ∘ u'.domRestrict A` is a closed -- embedding if and only if `u'.domRestrict A` is a closed embedding. -- Hence, we have proven our statement. From 5d5c893edf4e82545a3e356ccdb7b13fdc189114 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 19 May 2026 13:07:09 +0200 Subject: [PATCH 110/210] -- --- .../Analysis/Normed/Operator/Perturbation/StrictByFinite.lean | 2 -- 1 file changed, 2 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index aae74ee0a74085..c6fa05f6a0a0a5 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -375,8 +375,6 @@ end FiniteRank section FiniteDimQuotient --- TODO: better name --- TODO: use ∘ or ∘L ? The simp NF is ∘ /-- Consider `u : E →L[𝕜] F` and `B` a *complemented* finite dimensional subspace `F`. We have that `u` is strict with closed range if and only if `B.mkQL ∘L u` is strict with closed range. From 351900d70b0367ccfc057d470f2ed4601dbd4123 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 20 May 2026 15:12:21 +0200 Subject: [PATCH 111/210] start new approach --- .../Operator/Perturbation/StrictByFinite.lean | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index c6fa05f6a0a0a5..0f87e1eae5d09f 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -63,6 +63,64 @@ We do the proof in four steps. /-! ### Step 1 +We prove the theorem under the assumptions that +- `u` is surjective +- `u.ker` is disjoint from `A` (i.e. `u` is injective on `A`) +- `map u A` is closed +-/ + +theorem step0 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) + (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] + (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) + (uA_closed : IsClosed (map u.toLinearMap A : Set F)) : + IsStrictMap u ↔ IsStrictMap (u.domRestrict A) := by + -- Fix `S` an algebraic complement of `A` containing `u.ker`. It has finite dimension. + rcases h_ker.exists_isCompl with ⟨S, ker_le_S, S_compl_A⟩ + have : FiniteDimensional 𝕜 S := + quotientEquivOfIsCompl A S S_compl_A.symm |>.finiteDimensional + -- Because `A` is closed with finite codimension, `S` is in fact a topological complement + -- of `A`. + replace S_compl_A : IsTopCompl S A := + S_compl_A.symm.isTopCompl_of_finiteDimensional_quotient A_closed |>.symm + -- Because `u` is assumed surjective and `S ⊔ A = ⊤`, we have `map u S ⊔ map u A = ⊤`. + -- Furthermore, because the kernel of `u` is fully contained in `S`, we can show that + -- `map u S ⊓ map u A = ⊥`, so that `map u S` and `map u A` are in fact algebraic complements + -- of each other. + have uS_compl_uA : IsCompl (map u.toLinearMap S) (map u.toLinearMap A) := by + constructor + · rw [disjoint_iff, inf_comm, map_inf_eq_map_inf_comap, comap_map_eq, sup_eq_left.mpr ker_le_S, + S_compl_A.isCompl.symm.inf_eq_bot, Submodule.map_bot] + · rw [codisjoint_iff, ← Submodule.map_sup, S_compl_A.isCompl.sup_eq_top, Submodule.map_top, + h_range] + -- Since `map u S` has finite dimension, `map u A` has finite codimension. But we also know that + -- `map u A` is closed so, once again, `map u S` and `map u A` are in fact *topological* + -- complements of each other. + replace uS_compl_uA : IsTopCompl (map u.toLinearMap S) (map u.toLinearMap A) := + uS_compl_uA.symm.isTopCompl_of_isClosed_of_finiteDimensional uA_closed |>.symm + -- Thus, we have decomposed both the comain and the codomain into topopological complements, + -- and `u` preserves this decomposition, inducing maps `u₁ : S → map u S` and `u₂ : A → map u A`. + set u₁ : S →L[𝕜] map u.toLinearMap S := u.restrict (fun _ ↦ mem_map_of_mem) + set u₂ : A →L[𝕜] map u.toLinearMap A := u.restrict (fun _ ↦ mem_map_of_mem) + -- Using the corresponding isomorphisms `(S × A) ≃L[𝕜] E` and `(map u S × map u A) ≃L[𝕜] F`, + -- we have to show that the map `u₁.prodMap u₂ : S × A → map u S × map u A` is strict + -- if and only if `u₂ : A → map u A` is strict. + set Φ : (S × A) ≃L[𝕜] E := prodEquivOfIsTopCompl S A S_compl_A + set Ψ : (map u.toLinearMap S × map u.toLinearMap A) ≃L[𝕜] F := + prodEquivOfIsTopCompl _ _ uS_compl_uA + have u₁_surj : Surjective u₁ := surjective_mapsTo_image_restrict _ _ + have u₂_surj : Surjective u₂ := surjective_mapsTo_image_restrict _ _ + have u_eq : u = Ψ ∘ (u₁.prodMap u₂) ∘ Φ.symm := by + ext x + simp [Φ, Ψ, u₁, u₂, ← map_add, projectionL_add_projectionL_eq_self] + have u_restr_eq : u.domRestrict A = (map u.toLinearMap A).subtypeL ∘ u₂ := rfl + suffices IsStrictMap (Prod.map u₁ u₂) ↔ IsStrictMap u₂ by + rw [u_restr_eq, u_eq] + sorry + sorry + +/-! +### Step 1 + We prove the theorem under the assumptions that - `u` is surjective - `u.ker` is disjoint from `A` (i.e. `u` is injective on `A`) From 7f88202c9be913e845b1c7e91f4a513114371bc3 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 20 May 2026 15:23:45 +0200 Subject: [PATCH 112/210] tmp --- .../Operator/Perturbation/StrictByFinite.lean | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 0f87e1eae5d09f..08f50b9be96787 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -98,24 +98,31 @@ theorem step0 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) replace uS_compl_uA : IsTopCompl (map u.toLinearMap S) (map u.toLinearMap A) := uS_compl_uA.symm.isTopCompl_of_isClosed_of_finiteDimensional uA_closed |>.symm -- Thus, we have decomposed both the comain and the codomain into topopological complements, - -- and `u` preserves this decomposition, inducing maps `u₁ : S → map u S` and `u₂ : A → map u A`. - set u₁ : S →L[𝕜] map u.toLinearMap S := u.restrict (fun _ ↦ mem_map_of_mem) - set u₂ : A →L[𝕜] map u.toLinearMap A := u.restrict (fun _ ↦ mem_map_of_mem) + -- and `u` preserves this decomposition, inducing maps `uₛ : S → map u S` and `uₐ : A → map u A`. + set uₛ : S →L[𝕜] map u.toLinearMap S := u.restrict (fun _ ↦ mem_map_of_mem) + set uₐ : A →L[𝕜] map u.toLinearMap A := u.restrict (fun _ ↦ mem_map_of_mem) -- Using the corresponding isomorphisms `(S × A) ≃L[𝕜] E` and `(map u S × map u A) ≃L[𝕜] F`, - -- we have to show that the map `u₁.prodMap u₂ : S × A → map u S × map u A` is strict - -- if and only if `u₂ : A → map u A` is strict. + -- we have to show that the map `uₛ.prodMap uₐ : S × A → map u S × map u A` is strict + -- if and only if `uₐ : A → map u A` is strict. set Φ : (S × A) ≃L[𝕜] E := prodEquivOfIsTopCompl S A S_compl_A set Ψ : (map u.toLinearMap S × map u.toLinearMap A) ≃L[𝕜] F := prodEquivOfIsTopCompl _ _ uS_compl_uA - have u₁_surj : Surjective u₁ := surjective_mapsTo_image_restrict _ _ - have u₂_surj : Surjective u₂ := surjective_mapsTo_image_restrict _ _ - have u_eq : u = Ψ ∘ (u₁.prodMap u₂) ∘ Φ.symm := by + have uₛ_surj : Surjective uₛ := surjective_mapsTo_image_restrict _ _ + have uₐ_surj : Surjective uₐ := surjective_mapsTo_image_restrict _ _ + have u_eq : u = Ψ ∘ (uₛ.prodMap uₐ) ∘ Φ.symm := by ext x - simp [Φ, Ψ, u₁, u₂, ← map_add, projectionL_add_projectionL_eq_self] - have u_restr_eq : u.domRestrict A = (map u.toLinearMap A).subtypeL ∘ u₂ := rfl - suffices IsStrictMap (Prod.map u₁ u₂) ↔ IsStrictMap u₂ by - rw [u_restr_eq, u_eq] + simp [Φ, Ψ, uₛ, uₐ, ← map_add, projectionL_add_projectionL_eq_self] + have u_restr_eq : u.domRestrict A = (map u.toLinearMap A).subtypeL ∘ uₐ := rfl + suffices IsStrictMap (Prod.map uₛ uₐ) ↔ IsStrictMap uₐ by + rw [u_restr_eq, u_eq, ← (isEmbedding_subtypeL _).isStrictMap_iff] sorry + -- Note that these two maps are surjective, so they are strict if and only if + sorry + +theorem step1_of_step0 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) + (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] + (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) : + IsStrictMap u ↔ IsStrictMap (u.domRestrict A) ∧ IsClosed (map u.toLinearMap A : Set F) := by sorry /-! From 84ae636238c84a9a82d26c27f36257a9be81ba6b Mon Sep 17 00:00:00 2001 From: zw810-ctrl Date: Tue, 26 May 2026 01:18:12 -0400 Subject: [PATCH 113/210] Fix --- Mathlib/Topology/Maps/Strict/Basic.lean | 70 +++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index 83bae8f4523efb..49e2748f05cce5 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -7,8 +7,13 @@ module public import Mathlib.Topology.Maps.Basic public import Mathlib.Topology.Homeomorph.Quotient +public import Mathlib.Topology.Constructions.SumProd +public import Mathlib.Topology.Homeomorph.Lemmas public import Mathlib.Topology.Constructions public import Mathlib.Data.Setoid.Basic +public import Mathlib.GroupTheory.QuotientGroup.Basic +public import Mathlib.Topology.Algebra.Group.Basic +public import Mathlib.Topology.Algebra.Group.Quotient /-! # Bourbaki Strict Maps @@ -33,6 +38,17 @@ We provide several equivalent ways to characterize a strict map `f`: the canonical bijection `Quotient (Setoid.ker f) ≃ Set.range f` is a homeomorphism. * `Topology.isStrictMap_iff_isEmbedding_kerLift`: `f` is strict if and only if the canonical injection `Quotient (Setoid.ker f) → Y` (`Setoid.kerLift f`) is an embedding. + +### Group homomorphisms + +In general, the product (in the sense of `Prod.map`) of two strict maps need not be strict. +But thanks to `MonoidHom.isOpenQuotientMap_of_isQuotientMap`, we can replace `IsQuotientMap` +by `IsOpenQuotientMap` in the setting of group homomorphisms. Therefore we provide several +impotant properties of a strict group homomorphisms `f` : + +* `isStrictMap_iff_isOpenQuotientMap_rangeRestrict`: `f` is a strict group homomorphism if + and only if the `rangeRestrict` of `f` is an open quotient map. +* `isStrictMap_prodMap`: The product (in the sense of Prod.map) of group homomorphisms is strict -/ @[expose] public section @@ -153,4 +169,58 @@ lemma isEmbedding_iff_isStrictMap_injective : (Homeomorph.Quotient.congrRight <| by simp [f_inj.eq_iff]).trans Homeomorph.quotientBot exact f_strict.comp Φ.symm.isEmbedding +/-- Strict maps stay strict when we compose them with homeomorphisms -/ +lemma Homeomorph.comp_isStrictMap (e : X ≃ₜ Y) {f : Y → Z} (hf : IsStrictMap f) : + IsStrictMap (f ∘ e) := + by + rw [IsStrictMap] at hf ⊢ + let erange : Set.range (f ∘ e) ≃ₜ Set.range f := + Homeomorph.setCongr (by simp [Set.range_comp]) + convert erange.symm.isQuotientMap.comp (hf.comp e.isQuotientMap) using 1 + end Topology + +namespace MonoidHom +open Topology + +variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] +variable (f : G →* H) (g : G' →* H') + +/-- The range of a product of group homomorphisms is the product of their ranges. -/ +lemma range_prodMap : + (f.prodMap g).range = f.range.prod g.range := by + ext ⟨h, h'⟩ + simp only [Subgroup.mem_prod, MonoidHom.mem_range, MonoidHom.coe_prodMap, + Prod.map_apply, Prod.exists, Prod.mk.injEq] + tauto + +variable [TopologicalSpace G] [IsTopologicalGroup G] [TopologicalSpace H] + +/-- A quotient group homomorphism from a topological group is automatically an open quotient map. -/ +lemma isQuotientMap_iff_isOpenQuotientMap : + IsOpenQuotientMap f ↔ IsQuotientMap f := by + exact ⟨fun hf => hf.isQuotientMap, MonoidHom.isOpenQuotientMap_of_isQuotientMap⟩ + +/-- A group homomorphism is strict if and only if its rangeRestrict is an open quotient map. -/ +lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict : + IsStrictMap f ↔ IsOpenQuotientMap f.rangeRestrict := by + rw [isQuotientMap_iff_isOpenQuotientMap] + rfl + +variable [TopologicalSpace G'] [IsTopologicalGroup G'] [TopologicalSpace H'] + +noncomputable def rangeProdMapHomeomorph : + (f.prodMap g).range ≃ₜ f.range × g.range := + (Homeomorph.setCongr (by simp [range_prodMap, Subgroup.coe_prod])).trans + (Homeomorph.Set.prod _ _) + +/-- The product (in the sense of Prod.map) of group homomorphisms is strict -/ +lemma isStrictMap_prodMap (hf : IsStrictMap f) (hg : IsStrictMap g) : + IsStrictMap (f.prodMap g) := by + rw [isStrictMap_iff_isOpenQuotientMap_rangeRestrict] + have hf' := (isStrictMap_iff_isOpenQuotientMap_rangeRestrict (f := f)).mp hf + have hg' := (isStrictMap_iff_isOpenQuotientMap_rangeRestrict (f := g)).mp hg + convert (rangeProdMapHomeomorph (f := f) (g := g)).symm.isOpenQuotientMap.comp + (hf'.prodMap hg') using 1 + +end MonoidHom From 320f12e6badea950ea33248076eaed585b6f37e5 Mon Sep 17 00:00:00 2001 From: zw810-ctrl Date: Tue, 26 May 2026 01:37:52 -0400 Subject: [PATCH 114/210] doc: add docstring for MonoidHom.rangeProdMapHomeomorph --- Mathlib/Topology/Maps/Strict/Basic.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index 49e2748f05cce5..0520b79558ee4e 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -209,6 +209,7 @@ lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict : variable [TopologicalSpace G'] [IsTopologicalGroup G'] [TopologicalSpace H'] +/-- The range of a product of two group homomorphisms is homeomorphic to the product of ranges. -/ noncomputable def rangeProdMapHomeomorph : (f.prodMap g).range ≃ₜ f.range × g.range := (Homeomorph.setCongr (by simp [range_prodMap, Subgroup.coe_prod])).trans From a976cc10380c1869cdc6d907f1563a4a1d0341d9 Mon Sep 17 00:00:00 2001 From: Oliver Nash Date: Fri, 29 May 2026 12:00:24 +0100 Subject: [PATCH 115/210] Implement suggestions from CR --- Mathlib/Algebra/Group/Subgroup/Basic.lean | 9 ++++ Mathlib/Topology/Algebra/Group/Basic.lean | 7 ++++ Mathlib/Topology/Maps/Strict/Basic.lean | 50 +++++------------------ 3 files changed, 26 insertions(+), 40 deletions(-) diff --git a/Mathlib/Algebra/Group/Subgroup/Basic.lean b/Mathlib/Algebra/Group/Subgroup/Basic.lean index cfeaa4cb3bfbb6..880aa2d8f6317c 100644 --- a/Mathlib/Algebra/Group/Subgroup/Basic.lean +++ b/Mathlib/Algebra/Group/Subgroup/Basic.lean @@ -709,6 +709,15 @@ lemma ker_snd : ker (snd G G') = .prod ⊤ ⊥ := SetLike.ext fun _ => (iff_of_e end Ker +section Range + +@[to_additive range_prodMap] +lemma range_prodMap {G' : Type*} {N' : Type*} [Group G'] [Group N'] (f : G →* N) (g : G' →* N') : + (f.prodMap g).range = f.range.prod g.range := + SetLike.coe_injective Set.range_prodMap + +end Range + end MonoidHom namespace Subgroup diff --git a/Mathlib/Topology/Algebra/Group/Basic.lean b/Mathlib/Topology/Algebra/Group/Basic.lean index 6b132b67820f16..74bf4e1c50d99c 100644 --- a/Mathlib/Topology/Algebra/Group/Basic.lean +++ b/Mathlib/Topology/Algebra/Group/Basic.lean @@ -913,6 +913,13 @@ lemma MonoidHom.isOpenQuotientMap_of_isQuotientMap {A : Type*} [Group A] use x * k, hx rw [map_mul, hk, mul_one] +@[to_additive] +lemma MonoidHom.isQuotientMap_iff_isOpenQuotientMap {A : Type*} [Group A] + [TopologicalSpace A] [ContinuousMul A] {B : Type*} [Group B] [TopologicalSpace B] + {F : Type*} [FunLike F A B] [MonoidHomClass F A B] {φ : F} : + IsOpenQuotientMap φ ↔ IsQuotientMap φ := + ⟨fun hf => hf.isQuotientMap, MonoidHom.isOpenQuotientMap_of_isQuotientMap⟩ + @[to_additive] theorem IsTopologicalGroup.ext {G : Type*} [Group G] {t t' : TopologicalSpace G} (tg : @IsTopologicalGroup G t _) (tg' : @IsTopologicalGroup G t' _) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index 0520b79558ee4e..a69c49de9d0e5c 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -7,13 +7,10 @@ module public import Mathlib.Topology.Maps.Basic public import Mathlib.Topology.Homeomorph.Quotient -public import Mathlib.Topology.Constructions.SumProd -public import Mathlib.Topology.Homeomorph.Lemmas public import Mathlib.Topology.Constructions public import Mathlib.Data.Setoid.Basic -public import Mathlib.GroupTheory.QuotientGroup.Basic -public import Mathlib.Topology.Algebra.Group.Basic public import Mathlib.Topology.Algebra.Group.Quotient + /-! # Bourbaki Strict Maps @@ -44,7 +41,7 @@ We provide several equivalent ways to characterize a strict map `f`: In general, the product (in the sense of `Prod.map`) of two strict maps need not be strict. But thanks to `MonoidHom.isOpenQuotientMap_of_isQuotientMap`, we can replace `IsQuotientMap` by `IsOpenQuotientMap` in the setting of group homomorphisms. Therefore we provide several -impotant properties of a strict group homomorphisms `f` : +important properties of a strict group homomorphisms `f` : * `isStrictMap_iff_isOpenQuotientMap_rangeRestrict`: `f` is a strict group homomorphism if and only if the `rangeRestrict` of `f` is an open quotient map. @@ -172,34 +169,14 @@ lemma isEmbedding_iff_isStrictMap_injective : /-- Strict maps stay strict when we compose them with homeomorphisms -/ lemma Homeomorph.comp_isStrictMap (e : X ≃ₜ Y) {f : Y → Z} (hf : IsStrictMap f) : IsStrictMap (f ∘ e) := - by - rw [IsStrictMap] at hf ⊢ - let erange : Set.range (f ∘ e) ≃ₜ Set.range f := - Homeomorph.setCongr (by simp [Set.range_comp]) - convert erange.symm.isQuotientMap.comp (hf.comp e.isQuotientMap) using 1 + e.isQuotientMap.isStrictMap_iff.mp hf end Topology namespace MonoidHom -open Topology - -variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] -variable (f : G →* H) (g : G' →* H') - -/-- The range of a product of group homomorphisms is the product of their ranges. -/ -lemma range_prodMap : - (f.prodMap g).range = f.range.prod g.range := by - ext ⟨h, h'⟩ - simp only [Subgroup.mem_prod, MonoidHom.mem_range, MonoidHom.coe_prodMap, - Prod.map_apply, Prod.exists, Prod.mk.injEq] - tauto -variable [TopologicalSpace G] [IsTopologicalGroup G] [TopologicalSpace H] - -/-- A quotient group homomorphism from a topological group is automatically an open quotient map. -/ -lemma isQuotientMap_iff_isOpenQuotientMap : - IsOpenQuotientMap f ↔ IsQuotientMap f := by - exact ⟨fun hf => hf.isQuotientMap, MonoidHom.isOpenQuotientMap_of_isQuotientMap⟩ +variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] (f : G →* H) (g : G' →* H') + [TopologicalSpace G] [IsTopologicalGroup G] [TopologicalSpace H] /-- A group homomorphism is strict if and only if its rangeRestrict is an open quotient map. -/ lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict : @@ -209,19 +186,12 @@ lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict : variable [TopologicalSpace G'] [IsTopologicalGroup G'] [TopologicalSpace H'] -/-- The range of a product of two group homomorphisms is homeomorphic to the product of ranges. -/ -noncomputable def rangeProdMapHomeomorph : - (f.prodMap g).range ≃ₜ f.range × g.range := - (Homeomorph.setCongr (by simp [range_prodMap, Subgroup.coe_prod])).trans - (Homeomorph.Set.prod _ _) - -/-- The product (in the sense of Prod.map) of group homomorphisms is strict -/ +/-- The product (in the sense of `Prod.map`) of group homomorphisms is strict -/ lemma isStrictMap_prodMap (hf : IsStrictMap f) (hg : IsStrictMap g) : IsStrictMap (f.prodMap g) := by - rw [isStrictMap_iff_isOpenQuotientMap_rangeRestrict] - have hf' := (isStrictMap_iff_isOpenQuotientMap_rangeRestrict (f := f)).mp hf - have hg' := (isStrictMap_iff_isOpenQuotientMap_rangeRestrict (f := g)).mp hg - convert (rangeProdMapHomeomorph (f := f) (g := g)).symm.isOpenQuotientMap.comp - (hf'.prodMap hg') using 1 + rw [isStrictMap_iff_isOpenQuotientMap_rangeRestrict] at hf hg ⊢ + let aux : (f.prodMap g).range ≃ₜ f.range × g.range := + (Homeomorph.setCongr (by simp)).trans (Homeomorph.Set.prod _ _) + exact aux.symm.isOpenQuotientMap.comp (hf.prodMap hg) end MonoidHom From 42ba271fe761b3a4b2736fca95b47c1e25e06975 Mon Sep 17 00:00:00 2001 From: Oliver Nash Date: Fri, 29 May 2026 17:11:07 +0100 Subject: [PATCH 116/210] Add `TODO` for the `MonoidHom.isStrictMap_piMap` --- Mathlib/Topology/Maps/Strict/Basic.lean | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index a69c49de9d0e5c..ae50a84b4bb186 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -194,4 +194,6 @@ lemma isStrictMap_prodMap (hf : IsStrictMap f) (hg : IsStrictMap g) : (Homeomorph.setCongr (by simp)).trans (Homeomorph.Set.prod _ _) exact aux.symm.isOpenQuotientMap.comp (hf.prodMap hg) +-- TODO Add the lemma `isStrictMap_piMap` once `MonoidHom.piMap` has been defined. + end MonoidHom From 21c2effc131b108202b354ba4d599455086c8338 Mon Sep 17 00:00:00 2001 From: zw810-ctrl Date: Fri, 29 May 2026 13:50:42 -0400 Subject: [PATCH 117/210] upgrade strictness lemmas to iff and add symmetric versions --- Mathlib/Topology/Maps/Strict/Basic.lean | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index ae50a84b4bb186..bec2fa8395dac5 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -166,10 +166,15 @@ lemma isEmbedding_iff_isStrictMap_injective : (Homeomorph.Quotient.congrRight <| by simp [f_inj.eq_iff]).trans Homeomorph.quotientBot exact f_strict.comp Φ.symm.isEmbedding -/-- Strict maps stay strict when we compose them with homeomorphisms -/ -lemma Homeomorph.comp_isStrictMap (e : X ≃ₜ Y) {f : Y → Z} (hf : IsStrictMap f) : - IsStrictMap (f ∘ e) := - e.isQuotientMap.isStrictMap_iff.mp hf +/-- Strict maps are preserved and reflected when precomposing with a homeomorphism. -/ +lemma Homeomorph.isStrictMap_comp_iff (e : X ≃ₜ Y) {f : Y → Z} : + IsStrictMap (f ∘ e) ↔ IsStrictMap f := + e.isQuotientMap.isStrictMap_iff.symm + +/-- Strict maps are preserved and reflected when postcomposing with a homeomorphism. -/ +lemma Homeomorph.comp_isStrictMap_iff (e : Y ≃ₜ Z) {f : X → Y} : + IsStrictMap (e ∘ f) ↔ IsStrictMap f := + e.isEmbedding.isStrictMap_iff.symm end Topology From 0f18b7918f7a4001e37a10ad99660ee1ffe7498e Mon Sep 17 00:00:00 2001 From: Monica Omar <23701951+themathqueen@users.noreply.github.com> Date: Mon, 15 Jun 2026 13:09:27 +0100 Subject: [PATCH 118/210] Apply suggestions from code review Co-authored-by: Monica Omar <23701951+themathqueen@users.noreply.github.com> --- Mathlib/Algebra/Group/Subgroup/Basic.lean | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Mathlib/Algebra/Group/Subgroup/Basic.lean b/Mathlib/Algebra/Group/Subgroup/Basic.lean index 880aa2d8f6317c..37fe744d0967bd 100644 --- a/Mathlib/Algebra/Group/Subgroup/Basic.lean +++ b/Mathlib/Algebra/Group/Subgroup/Basic.lean @@ -709,15 +709,11 @@ lemma ker_snd : ker (snd G G') = .prod ⊤ ⊥ := SetLike.ext fun _ => (iff_of_e end Ker -section Range - @[to_additive range_prodMap] lemma range_prodMap {G' : Type*} {N' : Type*} [Group G'] [Group N'] (f : G →* N) (g : G' →* N') : (f.prodMap g).range = f.range.prod g.range := SetLike.coe_injective Set.range_prodMap -end Range - end MonoidHom namespace Subgroup From 9a889da88b33b865740a4bba203976e1c07d912b Mon Sep 17 00:00:00 2001 From: ADedecker Date: Mon, 15 Jun 2026 18:23:40 +0200 Subject: [PATCH 119/210] Reorganization --- .../Operator/Perturbation/StrictByFinite.lean | 247 ++++-------------- 1 file changed, 55 insertions(+), 192 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 08f50b9be96787..c24b60f5a83c7f 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -57,7 +57,7 @@ Let `u : E →L[𝕜] F` be a continuous linear map, and `A` a finite codimensio subspace of `E`. We want to show that `u` is strict with closed range if and only if `u.domRestrict A` is strict with closed range. -We do the proof in four steps. +We do the proof in five steps. -/ /-! @@ -69,7 +69,7 @@ We prove the theorem under the assumptions that - `map u A` is closed -/ -theorem step0 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) +theorem new_step1 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) (uA_closed : IsClosed (map u.toLinearMap A : Set F)) : @@ -78,10 +78,6 @@ theorem step0 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) rcases h_ker.exists_isCompl with ⟨S, ker_le_S, S_compl_A⟩ have : FiniteDimensional 𝕜 S := quotientEquivOfIsCompl A S S_compl_A.symm |>.finiteDimensional - -- Because `A` is closed with finite codimension, `S` is in fact a topological complement - -- of `A`. - replace S_compl_A : IsTopCompl S A := - S_compl_A.symm.isTopCompl_of_finiteDimensional_quotient A_closed |>.symm -- Because `u` is assumed surjective and `S ⊔ A = ⊤`, we have `map u S ⊔ map u A = ⊤`. -- Furthermore, because the kernel of `u` is fully contained in `S`, we can show that -- `map u S ⊓ map u A = ⊥`, so that `map u S` and `map u A` are in fact algebraic complements @@ -89,12 +85,13 @@ theorem step0 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) have uS_compl_uA : IsCompl (map u.toLinearMap S) (map u.toLinearMap A) := by constructor · rw [disjoint_iff, inf_comm, map_inf_eq_map_inf_comap, comap_map_eq, sup_eq_left.mpr ker_le_S, - S_compl_A.isCompl.symm.inf_eq_bot, Submodule.map_bot] - · rw [codisjoint_iff, ← Submodule.map_sup, S_compl_A.isCompl.sup_eq_top, Submodule.map_top, + S_compl_A.symm.inf_eq_bot, Submodule.map_bot] + · rw [codisjoint_iff, ← Submodule.map_sup, S_compl_A.sup_eq_top, Submodule.map_top, h_range] - -- Since `map u S` has finite dimension, `map u A` has finite codimension. But we also know that - -- `map u A` is closed so, once again, `map u S` and `map u A` are in fact *topological* - -- complements of each other. + -- Because `A` (resp. `map u A`) is closed and `S` (resp `map u S`) is closed, `A` and `S` + -- (resp `map u A` and `map u A`) are in fact *topological* complements of each other. + replace S_compl_A : IsTopCompl S A := + S_compl_A.symm.isTopCompl_of_finiteDimensional_quotient A_closed |>.symm replace uS_compl_uA : IsTopCompl (map u.toLinearMap S) (map u.toLinearMap A) := uS_compl_uA.symm.isTopCompl_of_isClosed_of_finiteDimensional uA_closed |>.symm -- Thus, we have decomposed both the comain and the codomain into topopological complements, @@ -111,162 +108,49 @@ theorem step0 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) have uₐ_surj : Surjective uₐ := surjective_mapsTo_image_restrict _ _ have u_eq : u = Ψ ∘ (uₛ.prodMap uₐ) ∘ Φ.symm := by ext x - simp [Φ, Ψ, uₛ, uₐ, ← map_add, projectionL_add_projectionL_eq_self] + simp [Φ, Ψ, uₛ, uₐ, ← map_add, projection_add_projection_eq_self] have u_restr_eq : u.domRestrict A = (map u.toLinearMap A).subtypeL ∘ uₐ := rfl suffices IsStrictMap (Prod.map uₛ uₐ) ↔ IsStrictMap uₐ by rw [u_restr_eq, u_eq, ← (isEmbedding_subtypeL _).isStrictMap_iff] - sorry - -- Note that these two maps are surjective, so they are strict if and only if - sorry - -theorem step1_of_step0 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) - (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] - (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) : - IsStrictMap u ↔ IsStrictMap (u.domRestrict A) ∧ IsClosed (map u.toLinearMap A : Set F) := by - sorry + sorry -- easy, missing API + sorry -- easy, missing API /-! -### Step 1 +### Step 2 We prove the theorem under the assumptions that - `u` is surjective - `u.ker` is disjoint from `A` (i.e. `u` is injective on `A`) - -The statement becomes: `u` is a quotient map if and only if `u.domRestrict A` is -a closed embedding. -/ -/-- The forward direction of step 1 in the proof of -`ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict`, which you should use instead. - -We prove it first for `u = K.mkQL`, because we have no analog of `Submodule.liftQL` for arbitrary -linear quotient maps; when this is solved, this should be merged with `step1_forward` below. -/ -theorem step1_foward' (A : Submodule 𝕜 E) (K : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) - [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (K_disj_A : Disjoint K A) : - IsClosedEmbedding (K.mkQL.domRestrict A) := by - constructor - · -- We show that `K.mkQL.domRestrict A` is an embedding by exhibiting a continuous left inverse. - -- Fix `S` an algebraic complement of `A` containing `K`. - rcases K_disj_A.exists_isCompl with ⟨S, K_le_S, S_compl_A⟩ - -- Because `A` is closed with finite codimension, `S` is in fact a topological complement - -- of `A`. - replace S_compl_A : IsTopCompl S A := - S_compl_A.symm.isTopCompl_of_finiteDimensional_quotient A_closed |>.symm - -- Thus the projection onto `A` along `S` is continuous, and it vanishes on `K`. - -- Hence it defines a map `E ⧸ K →L[𝕜] A`, which is our left inverse. - let s : E ⧸ K →L[𝕜] A := K.liftQL (A.projectionOntoL S S_compl_A.symm) (by simpa) - have leftInv : LeftInverse s (restrict A K.mkQ) := fun x ↦ by simp [s] - refine .of_leftInverse leftInv s.continuous (by fun_prop) - · -- The subspace `K.mkQL ⁻¹' K.mkQL '' A` contains the closed and finite codimension subspace - -- `A`, hence it is closed. By definition of the quotient topology, this shows that - -- `K.mkQL.domRestrict A` has closed range. - rw [← K.isQuotientMap_mkQ.isClosed_preimage, ContinuousLinearMap.coe_domRestrict, - range_restrict, ← ContinuousLinearMap.coe_coe, ← map_coe, ← comap_coe K.mkQ] - exact isClosed_mono_of_finiteDimensional_quotient A_closed (le_comap_map _ A) - -omit [IsTopologicalAddGroup F] [ContinuousSMul 𝕜 F] in -/-- The forward direction of step 1 in the proof of -`ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict`, which you should use instead. -/ -theorem step1_foward (u : E →L[𝕜] F) (A : Submodule 𝕜 E) - (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] - (h_ker : Disjoint u.ker A) (h_quot : IsQuotientMap u) : - IsClosedEmbedding (u.domRestrict A) := by - -- Because `u` is a quotient linear map, we can identify it with "the" quotient map - -- `E → E ⧸ u.ker`, for which we have proven the result above. - -- TODO: there should be API - set Φ : (E ⧸ u.ker) ≃L[𝕜] F := - { toLinearEquiv := u.toLinearMap.quotKerEquivOfSurjective h_quot.surjective - continuous_toFun := continuous_quot_lift _ h_quot.continuous - continuous_invFun := h_quot.continuous_iff.mpr <| u.ker.continuous_mkQ.congr fun x ↦ by - simp [← ContinuousLinearMap.coe_coe] } - -- TODO: there should be API - have Φ_clemb : IsClosedEmbedding Φ := Φ.toHomeomorph.isClosedEmbedding - have eq : u.domRestrict A = Φ ∘L u.ker.mkQL.domRestrict A := rfl - simpa [eq, Φ_clemb.of_comp_iff] using step1_foward' A u.ker A_closed h_ker - -/-- The backward direction of step 1 in the proof of -`ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict`, which you should use instead. - -Note the hypothesis `h_ker` is implied `h_clemb`, but since this is a private theorem -we just write the most convenient statement to prove and use. -/ -theorem step1_backward [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) - (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] - (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) - (h_clemb : IsClosedEmbedding (u.domRestrict A)) : - IsQuotientMap u := by - -- Fix `S` an algebraic complement of `A` containing `u.ker`. It has finite dimension. - rcases h_ker.exists_isCompl with ⟨S, ker_le_S, S_compl_A⟩ - have : FiniteDimensional 𝕜 S := - quotientEquivOfIsCompl A S S_compl_A.symm |>.finiteDimensional - -- Because `A` is closed with finite codimension, `S` is in fact a topological complement of `A`. - replace S_compl_A : IsTopCompl S A := - S_compl_A.symm.isTopCompl_of_finiteDimensional_quotient A_closed |>.symm - -- By assumption, `map u A` is closed. - have uA_closed : IsClosed (map u.toLinearMap A : Set F) := by - simpa [← range_restrict] using h_clemb.isClosed_range - -- Because `u` is assumed surjective and `S ⊔ A = ⊤`, we have `map u S ⊔ map u A = ⊤`. - -- Furthermore, because the kernel of `u` is fully contained in `S`, we can show that - -- `map u S ⊓ map u A = ⊥`, so that `map u S` and `map u A` are in fact algebraic complements - -- of each other. - have uS_compl_uA : IsCompl (map u.toLinearMap S) (map u.toLinearMap A) := by - constructor - · rw [disjoint_iff, inf_comm, map_inf_eq_map_inf_comap, comap_map_eq, sup_eq_left.mpr ker_le_S, - S_compl_A.isCompl.symm.inf_eq_bot, Submodule.map_bot] - · rw [codisjoint_iff, ← Submodule.map_sup, S_compl_A.isCompl.sup_eq_top, Submodule.map_top, - h_range] - -- Since `map u S` has finite dimension, `map u A` has finite codimension. But we also know that - -- `map u A` is closed so, once again, `map u S` and `map u A` are in fact *topological* - -- complements of each other. - replace uS_compl_uA : IsTopCompl (map u.toLinearMap S) (map u.toLinearMap A) := - uS_compl_uA.symm.isTopCompl_of_isClosed_of_finiteDimensional uA_closed |>.symm - -- Thus, we have decomposed both the comain and the codomain into topopological complements. - -- Using the corresponding isomorphisms `(S × A) ≃L[𝕜] E` and `(map u S × map u A) ≃L[𝕜] F`, - -- we have to show that the map `u₁.prodMap u₂ : S × A → map u S × map u A` is a quotient map. - set Φ : (S × A) ≃L[𝕜] E := prodEquivOfIsTopCompl S A S_compl_A - set Ψ : (map u.toLinearMap S × map u.toLinearMap A) ≃L[𝕜] F := - prodEquivOfIsTopCompl _ _ uS_compl_uA - set u₁ : S →L[𝕜] map u.toLinearMap S := u.restrict (fun _ ↦ mem_map_of_mem) - set u₂ : A →L[𝕜] map u.toLinearMap A := u.restrict (fun _ ↦ mem_map_of_mem) - have u₁_surj : Surjective u₁ := surjective_mapsTo_image_restrict _ _ - have u₂_surj : Surjective u₂ := surjective_mapsTo_image_restrict _ _ - have eq : u = Ψ ∘ (u₁.prodMap u₂) ∘ Φ.symm := by - ext x - simp [Φ, Ψ, u₁, u₂, ← map_add, projectionL_add_projectionL_eq_self] - suffices IsQuotientMap (Prod.map u₁ u₂) from eq ▸ - (Ψ.toHomeomorph.isQuotientMap.comp this |>.comp Φ.symm.toHomeomorph.isQuotientMap) - -- Since linear quotient maps are automatically open, and since the product of two open quotient - -- maps is a quotient map, this reduces to showing that both `u₁` and `u₂` are quotient maps. - refine IsOpenQuotientMap.prodMap ?_ ?_ |>.isQuotientMap <;> - apply AddMonoidHom.isOpenQuotientMap_of_isQuotientMap ?_ - -- `u₁` is a quotient map because it is a surjective linear map between finite dimensional spaces. - · refine ContinuousLinearMap.isQuotientMap_of_finiteDimensional u₁ - (u₁.range_eq_top_of_surjective u₁_surj) - -- `u₂` is strict because `(map u A).subtype ∘ u₂ = u.restrict A` is an embedding (hence strict) - -- by assumptions. Since `u₂` is surjective, it is a quotient map, and we are done. - · simp_rw [isQuotientMap_iff_isStrictMap_surjective, u₂_surj, and_true, - (map u.toLinearMap A).isEmbedding_subtype.isStrictMap_iff] - exact h_clemb.isStrictMap - -theorem step1 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) +theorem new_step2 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) : - IsQuotientMap u ↔ IsClosedEmbedding (u.domRestrict A) := - ⟨step1_foward u A A_closed h_ker, step1_backward u A A_closed h_ker h_range⟩ + IsStrictMap u ↔ IsStrictMap (u.domRestrict A) ∧ IsClosed (map u.toLinearMap A : Set F) := by + -- To reduce to step 1, it suffices to show that `IsStrictMap u → IsClosed (map u A)`. + suffices IsStrictMap u → IsClosed (map u.toLinearMap A : Set F) by grind only [new_step1] + -- So, we assume that `u` is strict. Because it is surjective, it is a quotient map. + intro u_strict + have u_quot : IsQuotientMap u := by + rw [LinearMap.range_eq_top, coe_coe] at h_range + simp [isQuotientMap_iff_isStrictMap_surjective, h_range, u_strict] + -- Hence, we have to check that `comap u (map u A)` is closed. This follows from + -- `A ≤ comap u (map u A)` and the fact that `A` is closed with finite codimension. + rw [← u_quot.isClosed_preimage, ← coe_coe, ← Submodule.comap_coe] + exact Submodule.isClosed_mono_of_finiteDimensional_quotient A_closed (le_comap_map _ _) /-! -### Step 2 +### Step 3 We prove the theorem under the assumptions that - `u` has closed range - `u.ker` is disjoint from `A` (i.e. `u` is injective on `A`) - -The statement becomes: `u` is strict if and only if `Set.restrict A u` is a closed embedding. -/ -theorem step2 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) +theorem new_step3 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_range : IsClosed (u.range : Set F)) : - IsStrictMap u ↔ IsClosedEmbedding (u.domRestrict A) := by + IsStrictMap u ↔ IsStrictMap (u.domRestrict A) ∧ IsClosed (map u.toLinearMap A : Set F) := by -- Let `F' := u.range` and `i : F' →L[𝕜] F` be the inclusion map. By assumption, -- `i` is a closed embedding. set F' : Submodule 𝕜 F := u.range @@ -276,63 +160,43 @@ theorem step2 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) -- and we clearly have `u.domRestrict A = i ∘ u'.domRestrict A` as well. set u' : E →L[𝕜] F' := u.rangeRestrict have range_u' : u'.range = ⊤ := u.range_rangeRestrict - have u'_surj : Surjective u' := u.surjective_rangeRestrict have eq1 : u = i ∘L u' := rfl have eq2 : u.domRestrict A = i ∘L (u'.domRestrict A) := rfl - -- Note that we still have that `u'.ker = u.ker` is disjoint from `A`. - have ker_u' : u'.ker = u.ker := u.ker_rangeRestrict - -- Thus we can apply step 1 to `u'`, and we get that `u'` is strict if and only if - -- `u'.domRestrict A` is a closed embedding. - have step1_output : IsQuotientMap u' ↔ IsClosedEmbedding (u'.domRestrict A) := - step1 u' A A_closed (ker_u' ▸ h_ker) range_u' - -- On the other hand: - -- * since `i` is an embedding, `u = i ∘ u'` is strict if and only if `u'` is strict - -- (i.e a quotient map, by surjectivity); - -- * since `i` is a closed embedding, `u.domRestrict A = i ∘ u'.domRestrict A` is a closed - -- embedding if and only if `u'.domRestrict A` is a closed embedding. - -- Hence, we have proven our statement. - simp_rw [eq2, eq1, ContinuousLinearMap.coe_comp', i_clemb.of_comp_iff, ← i_clemb.isStrictMap_iff, - ← step1_output, isQuotientMap_iff_isStrictMap_surjective, u'_surj, and_true] + -- We can rewrite our goal in terms of `u'`. + simp_rw [eq2, eq1, coe_comp, ← i_clemb.isEmbedding.isStrictMap_iff, toLinearMap_comp, map_comp, + map_coe i.toLinearMap, coe_coe, ← i_clemb.isClosed_iff_image_isClosed] + -- We finish by applying step 2 (using that `u.ker = u'.ker`). + exact new_step2 u' A A_closed (u.ker_rangeRestrict ▸ h_ker) range_u' /-! -### Step 3 +### Step 4 We prove the theorem under the assumption that `u.ker` is disjoint from `A` (i.e. `u` is injective on `A`). - -The statement becomes: `u` is strict with closed range if and only if `Set.restrict A u` is -a closed embedding. -/ -theorem step3 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) +theorem new_step4 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) : - (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ IsClosedEmbedding (u.domRestrict A) := by - -- It suffices to show that, if `u.domRestrict A` is a closed embedding, then the range of `u` - -- is closed. Indeed, if this is the case, both sides of the equivalence imply that `u` has - -- closed range, so we can invoke step 2 to prove each direction. - suffices IsClosedEmbedding (u.domRestrict A) → IsClosed (u.range : Set F) by - rw [← iff_self_and] at this - rw [this, and_congr_left_iff] - exact step2 u A A_closed h_ker - -- Thus, assume that `u.domRestrict A` is a closed embedding. In particular, `map u A` is closed. - intro h_clemb - rw [isClosedEmbedding_iff, ← ContinuousLinearMap.coe_coe, ← LinearMap.coe_range, - ContinuousLinearMap.toLinearMap_domRestrict, LinearMap.range_domRestrict] at h_clemb - -- Fix `S` an algebraic complement of `A` containing `u.ker`. Note that `S` has finite - -- dimension. - rcases A.exists_isCompl with ⟨S, A_compl_S⟩ + (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ + IsStrictMap (u.domRestrict A) ∧ IsClosed (map u.toLinearMap A : Set F) := by + -- To reduce to step 3, it suffices to show that, if `map u A` is closed, then so is `u.range`. + suffices IsClosed (map u.toLinearMap A : Set F) → IsClosed (u.range : Set F) by + grind only [new_step3] + -- So, we assume that `map u A` is closed. + intro uA_closed + -- Fix `S` an algebraic complement of `A` containing `u.ker`. It has finite dimension. + rcases h_ker.exists_isCompl with ⟨S, ker_le_S, S_compl_A⟩ have : FiniteDimensional 𝕜 S := - quotientEquivOfIsCompl A S A_compl_S |>.finiteDimensional - -- Because `map u A` is closed and `map u S` is finite dimensional, we get that - -- `u.range = map u A ⊔ map u S` is closed. - have : u.range = (map u.toLinearMap A ⊔ map u.toLinearMap S) := by - rw [← Submodule.map_sup, A_compl_S.sup_eq_top, Submodule.map_top] - exact this ▸ Submodule.isClosed_sup_finiteDimensional _ _ h_clemb.2 + quotientEquivOfIsCompl A S S_compl_A.symm |>.finiteDimensional + -- It follows that `u.range = map u A ⊔ map u S` is closed. + rw [← Submodule.map_top, ← S_compl_A.symm.sup_eq_top, Submodule.map_sup] + exact isClosed_sup_finiteDimensional _ _ uA_closed + /-! -### Step 4 +### Step 5 -We now deduce from the two previous step the full strength of the theorem. +We now deduce from the previous steps the full strength of the theorem. -/ /-- Consider `u : E →L[𝕜] F` and `A` a closed subspace of `E` of finite codimension. @@ -367,12 +231,11 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Sp have A_mapsTo_B : MapsTo π A B := fun _ ↦ by simp [← comap_B] have B_closed : IsClosed (B : Set <| E ⧸ N) := by rwa [← π_quot.isQuotientMap.isClosed_preimage, ← π.coe_coe, ← comap_coe, comap_B] - -- Thus, we can apply step 3 to `v`: we get that `v` is strict with closed range if + -- Thus, we can apply step 4 to `v`: we get that `v` is strict with closed range if -- and only if `v.domRestrict B` is strict with closed range. have step3_output : (IsStrictMap v ∧ IsClosed (v.range : Set F)) ↔ (IsStrictMap (v.domRestrict B) ∧ IsClosed (map v.toLinearMap B : Set F)) := by - simp [step3 v B B_closed v_ker, isClosedEmbedding_iff, ContinuousLinearMap.coe_domRestrict, - ← range_restrict, isEmbedding_iff_isStrictMap_injective, v_restr_inj] + simp [new_step4 v B B_closed v_ker, coe_domRestrict, ← range_restrict] -- Now, we wish to reduce our statement about `u` and `u.domRestrict A` -- to what we know about `v` and `v.domRestrict B`. -- First, it is clear that `range u = range v` and `map u A = map v B`. @@ -382,7 +245,7 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Sp -- Furthermore, since `π` is a quotient map and `u = v ∘ π`, we have that `u` is strict -- if and only if `v` is strict. have strict_iff : IsStrictMap u ↔ IsStrictMap v := by - rw [← v_comp_π_eq_u, ContinuousLinearMap.coe_comp', ← π_quot.isQuotientMap.isStrictMap_iff] + rw [← v_comp_π_eq_u, coe_comp, ← π_quot.isQuotientMap.isStrictMap_iff] -- Now, recall the equality `A = comap π B`; it ensures that the restriction -- `π' : A → B` of the open quotient map `π` is *still* an (open quotient map). set π' : A →L[𝕜] B := π.restrict A_mapsTo_B @@ -394,7 +257,7 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Sp -- Because `v.domRestrict B ∘ π' = u.domRestrict A`, it follows that `u.domRestrict A` -- is strict if and only if `v.domRestrict B` is strict. have strict_iff_restrict : IsStrictMap (u.domRestrict A) ↔ IsStrictMap (v.domRestrict B) := by - rw [← v_comp_π'_eq_u, ContinuousLinearMap.coe_comp', ← π'_quot.isQuotientMap.isStrictMap_iff] + rw [← v_comp_π'_eq_u, coe_comp, ← π'_quot.isQuotientMap.isStrictMap_iff] -- Thus, we are done! rw [strict_iff, strict_iff_restrict, ← range_eq, ← image_eq] exact step3_output From f95160b159b21d4e35078458ab29d6f13f2a9040 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 16 Jun 2026 17:03:47 +0200 Subject: [PATCH 120/210] feat: iff version of IsOpenQuotientMap.prodMap --- Mathlib/Topology/Constructions/SumProd.lean | 10 ---- Mathlib/Topology/Maps/Basic.lean | 6 +++ Mathlib/Topology/Maps/OpenQuotient.lean | 58 ++++++++++++++++++++- Mathlib/Topology/Maps/Strict/Basic.lean | 23 +++++--- 4 files changed, 78 insertions(+), 19 deletions(-) diff --git a/Mathlib/Topology/Constructions/SumProd.lean b/Mathlib/Topology/Constructions/SumProd.lean index 47f5604db505be..c772e2d4c08641 100644 --- a/Mathlib/Topology/Constructions/SumProd.lean +++ b/Mathlib/Topology/Constructions/SumProd.lean @@ -494,12 +494,6 @@ theorem isOpen_prod_iff' {s : Set X} {t : Set Y} : simp only [st.1.ne_empty, st.2.ne_empty, or_false] at H exact H.1.prod H.2 -theorem isQuotientMap_fst [Nonempty Y] : IsQuotientMap (Prod.fst : X × Y → X) := - isOpenMap_fst.isQuotientMap continuous_fst Prod.fst_surjective - -theorem isQuotientMap_snd [Nonempty X] : IsQuotientMap (Prod.snd : X × Y → Y) := - isOpenMap_snd.isQuotientMap continuous_snd Prod.snd_surjective - theorem closure_prod_eq {s : Set X} {t : Set Y} : closure (s ×ˢ t) = closure s ×ˢ closure t := ext fun ⟨a, b⟩ => by simp_rw [mem_prod, mem_closure_iff_nhdsWithin_neBot, nhdsWithin_prod_eq, prod_neBot] @@ -608,10 +602,6 @@ lemma isEmbedding_prodMkLeft (y : Y) : IsEmbedding (fun x : X ↦ (x, y)) := lemma isEmbedding_prodMkRight (x : X) : IsEmbedding (Prod.mk x : Y → X × Y) := .of_comp (.prodMk_right x) continuous_snd .id -theorem IsOpenQuotientMap.prodMap {f : X → Y} {g : Z → W} (hf : IsOpenQuotientMap f) - (hg : IsOpenQuotientMap g) : IsOpenQuotientMap (Prod.map f g) := - ⟨.prodMap hf.1 hg.1, .prodMap hf.2 hg.2, .prodMap hf.3 hg.3⟩ - theorem TopologicalSpace.prod_mono {α β : Type*} {σ₁ σ₂ : TopologicalSpace α} {τ₁ τ₂ : TopologicalSpace β} (hσ : σ₁ ≤ σ₂) (hτ : τ₁ ≤ τ₂) : @instTopologicalSpaceProd α β σ₁ τ₁ ≤ @instTopologicalSpaceProd α β σ₂ τ₂ := diff --git a/Mathlib/Topology/Maps/Basic.lean b/Mathlib/Topology/Maps/Basic.lean index 95ca6b0a625fdb..427fa3a19c8be7 100644 --- a/Mathlib/Topology/Maps/Basic.lean +++ b/Mathlib/Topology/Maps/Basic.lean @@ -369,6 +369,12 @@ protected theorem id : IsOpenMap (@id X) := fun s hs => by rwa [image_id] protected theorem comp (hg : IsOpenMap g) (hf : IsOpenMap f) : IsOpenMap (g ∘ f) := fun s hs => by rw [image_comp]; exact hg _ (hf _ hs) +/-- If `g ∘ f` is open, where `f` is continuous and surjective, then `g` is open. -/ +theorem of_comp (hf : Continuous f) (f_surj : Surjective f) (h : IsOpenMap (g ∘ f)) : + IsOpenMap g := fun s hs => by + rw [← f_surj.image_preimage s, ← image_comp] + exact h _ (hs.preimage hf) + theorem isOpen_range (hf : IsOpenMap f) : IsOpen (range f) := by rw [← image_univ] exact hf _ isOpen_univ diff --git a/Mathlib/Topology/Maps/OpenQuotient.lean b/Mathlib/Topology/Maps/OpenQuotient.lean index ccbd3c06193cac..c3905a4cb2dbee 100644 --- a/Mathlib/Topology/Maps/OpenQuotient.lean +++ b/Mathlib/Topology/Maps/OpenQuotient.lean @@ -29,7 +29,8 @@ public section open Filter Function Set Topology -variable {X Y Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] {f : X → Y} +variable {X Y Z W : Type*} [TopologicalSpace X] [TopologicalSpace Y] + [TopologicalSpace Z] [TopologicalSpace W] {f : X → Y} namespace IsOpenQuotientMap @@ -50,6 +51,15 @@ theorem comp {g : Y → Z} (hg : IsOpenQuotientMap g) (hf : IsOpenQuotientMap f) IsOpenQuotientMap (g ∘ f) := ⟨.comp hg.1 hf.1, .comp hg.2 hf.2, .comp hg.3 hf.3⟩ +theorem of_comp {g : Y → Z} (hf : Continuous f) (f_surj : Surjective f) (hg : Continuous g) + (h : IsOpenQuotientMap (g ∘ f)) : IsOpenQuotientMap g := + ⟨.of_comp h.surjective, hg, .of_comp hf f_surj h.isOpenMap ⟩ + +theorem of_comp_iff {g : Y → Z} (hf : IsOpenQuotientMap f) : + IsOpenQuotientMap (g ∘ f) ↔ IsOpenQuotientMap g := + ⟨fun h ↦ .of_comp hf.continuous hf.surjective + (hf.isQuotientMap.continuous_iff.mpr h.continuous) h, fun hg ↦ hg.comp hf⟩ + theorem map_nhds_eq (h : IsOpenQuotientMap f) (x : X) : map f (𝓝 x) = 𝓝 (f x) := le_antisymm h.continuous.continuousAt <| h.isOpenMap.nhds_le _ @@ -61,6 +71,10 @@ theorem continuousAt_comp_iff (h : IsOpenQuotientMap f) {g : Y → Z} {x : X} : ContinuousAt (g ∘ f) x ↔ ContinuousAt g (f x) := by simp only [ContinuousAt, ← h.map_nhds_eq, tendsto_map'_iff, comp_def] +theorem isOpenMap_iff (hf : IsOpenQuotientMap f) {g : Y → Z} : + IsOpenMap g ↔ IsOpenMap (g ∘ f) := + ⟨fun hg ↦ hg.comp hf.isOpenMap, fun h ↦ .of_comp hf.continuous hf.surjective h⟩ + theorem dense_preimage_iff (h : IsOpenQuotientMap f) {s : Set Y} : Dense (f ⁻¹' s) ↔ Dense s := ⟨fun hs ↦ h.surjective.denseRange.dense_of_mapsTo h.continuous hs (mapsTo_preimage _ _), fun hs ↦ hs.preimage h.isOpenMap⟩ @@ -76,6 +90,48 @@ theorem baireSpace {f : X → Y} [BaireSpace X] (hf : IsOpenQuotientMap f) : end IsOpenQuotientMap +section Prod + +theorem isOpenQuotientMap_fst [Nonempty Y] : IsOpenQuotientMap (Prod.fst : X × Y → X) := + ⟨Prod.fst_surjective, continuous_fst, isOpenMap_fst⟩ + +theorem isOpenQuotientMap_snd [Nonempty X] : IsOpenQuotientMap (Prod.snd : X × Y → Y) := + ⟨Prod.snd_surjective, continuous_snd, isOpenMap_snd⟩ + +theorem isQuotientMap_fst [Nonempty Y] : IsQuotientMap (Prod.fst : X × Y → X) := + isOpenQuotientMap_fst.isQuotientMap + +theorem isQuotientMap_snd [Nonempty X] : IsQuotientMap (Prod.snd : X × Y → Y) := + isOpenQuotientMap_snd.isQuotientMap + +theorem IsOpenQuotientMap.prodMap {f : X → Y} {g : Z → W} (hf : IsOpenQuotientMap f) + (hg : IsOpenQuotientMap g) : IsOpenQuotientMap (Prod.map f g) := + ⟨.prodMap hf.1 hg.1, .prodMap hf.2 hg.2, .prodMap hf.3 hg.3⟩ + +theorem isOpenQuotientMap_prodMap_iff [Nonempty X] [Nonempty Z] {f : X → Y} {g : Z → W} : + IsOpenQuotientMap (Prod.map f g) ↔ IsOpenQuotientMap f ∧ IsOpenQuotientMap g := by + have : Nonempty Y := .map f inferInstance + have : Nonempty W := .map g inferInstance + refine ⟨fun h ↦ ⟨?_, ?_⟩, fun ⟨hf, hg⟩ ↦ hf.prodMap hg⟩ + · rw [← (isOpenQuotientMap_fst (Y := Z)).of_comp_iff] + exact isOpenQuotientMap_fst.comp h + · rw [← (isOpenQuotientMap_snd (X := X)).of_comp_iff] + exact isOpenQuotientMap_snd.comp h + +end Prod + +/-- Open quotient maps are preserved by precomposing with a homeomorphism. -/ +lemma Homeomorph.isOpenQuotient_comp_iff (e : X ≃ₜ Y) {f : Y → Z} : + IsOpenQuotientMap (f ∘ e) ↔ IsOpenQuotientMap f := + ⟨fun h ↦ by simpa [comp_assoc] using h.comp e.symm.isOpenQuotientMap, + fun hf ↦ hf.comp e.isOpenQuotientMap⟩ + +/-- Open quotient maps are preserved by postcomposing with a homeomorphism. -/ +lemma Homeomorph.comp_isOpenQuotientMap_iff (e : Y ≃ₜ Z) {f : X → Y} : + IsOpenQuotientMap (e ∘ f) ↔ IsOpenQuotientMap f := + ⟨fun h ↦ by simpa [← comp_assoc] using e.symm.isOpenQuotientMap.comp h, + fun hf ↦ e.isOpenQuotientMap.comp hf⟩ + theorem Topology.IsInducing.isOpenQuotientMap_of_surjective (ind : IsInducing f) (surj : Function.Surjective f) : IsOpenQuotientMap f where surjective := surj diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index bec2fa8395dac5..99ba90badbbabb 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -184,20 +184,27 @@ variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] (f : G [TopologicalSpace G] [IsTopologicalGroup G] [TopologicalSpace H] /-- A group homomorphism is strict if and only if its rangeRestrict is an open quotient map. -/ -lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict : +@[to_additive] lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict : IsStrictMap f ↔ IsOpenQuotientMap f.rangeRestrict := by rw [isQuotientMap_iff_isOpenQuotientMap] rfl -variable [TopologicalSpace G'] [IsTopologicalGroup G'] [TopologicalSpace H'] +variable {f g} [TopologicalSpace G'] [IsTopologicalGroup G'] [TopologicalSpace H'] -/-- The product (in the sense of `Prod.map`) of group homomorphisms is strict -/ -lemma isStrictMap_prodMap (hf : IsStrictMap f) (hg : IsStrictMap g) : - IsStrictMap (f.prodMap g) := by - rw [isStrictMap_iff_isOpenQuotientMap_rangeRestrict] at hf hg ⊢ - let aux : (f.prodMap g).range ≃ₜ f.range × g.range := +/-- The product (in the sense of `Prod.map`) of group homomorphisms is strict if and only if each +of the morphisms is strict. -/ +@[to_additive] lemma isStrictMap_prodMap_iff : + IsStrictMap (f.prodMap g) ↔ IsStrictMap f ∧ IsStrictMap g := by + simp_rw [isStrictMap_iff_isOpenQuotientMap_rangeRestrict] + let Φ : (f.prodMap g).range ≃ₜ f.range × g.range := (Homeomorph.setCongr (by simp)).trans (Homeomorph.Set.prod _ _) - exact aux.symm.isOpenQuotientMap.comp (hf.prodMap hg) + have eq : Φ ∘ (f.prodMap g).rangeRestrict = f.rangeRestrict.prodMap g.rangeRestrict := rfl + rw [← Φ.comp_isOpenQuotientMap_iff, eq, MonoidHom.coe_prodMap, isOpenQuotientMap_prodMap_iff] + +/-- The product (in the sense of `Prod.map`) of strict group homomorphisms is strict -/ +@[to_additive] lemma IsStrictMap.prodMap (hf : IsStrictMap f) (hg : IsStrictMap g) : + IsStrictMap (f.prodMap g) := + isStrictMap_prodMap_iff.mpr ⟨hf, hg⟩ -- TODO Add the lemma `isStrictMap_piMap` once `MonoidHom.piMap` has been defined. From 2038cee82dbb6a0b1c0a0ddfe5f9aa7bb2e989f8 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 16 Jun 2026 17:52:48 +0200 Subject: [PATCH 121/210] Better --- Mathlib/Topology/Constructions/SumProd.lean | 5 +++++ Mathlib/Topology/Maps/OpenQuotient.lean | 14 +++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Mathlib/Topology/Constructions/SumProd.lean b/Mathlib/Topology/Constructions/SumProd.lean index c772e2d4c08641..58414f4e1718d7 100644 --- a/Mathlib/Topology/Constructions/SumProd.lean +++ b/Mathlib/Topology/Constructions/SumProd.lean @@ -369,6 +369,11 @@ theorem ContinuousAt.comp₂_of_eq {f : Y × Z → W} {g : X → Y} {h : X → Z rw [← e] at hf exact hf.comp₂ hg hh +theorem continuous_prodMap_iff [Nonempty Z] [Nonempty W] {f : Z → X} {g : W → Y} : + Continuous (Prod.map f g) ↔ Continuous f ∧ Continuous g := by + simp [continuous_iff_continuousAt, ContinuousAt, nhds_prod_eq, tendsto_iff_comap, + comap_prodMap_prod, forall_and] + /-- Continuous functions on products are continuous in their first argument -/ theorem Continuous.curry_left {f : X × Y → Z} (hf : Continuous f) {y : Y} : Continuous fun x ↦ f (x, y) := diff --git a/Mathlib/Topology/Maps/OpenQuotient.lean b/Mathlib/Topology/Maps/OpenQuotient.lean index c3905a4cb2dbee..698564643fcfbf 100644 --- a/Mathlib/Topology/Maps/OpenQuotient.lean +++ b/Mathlib/Topology/Maps/OpenQuotient.lean @@ -108,15 +108,19 @@ theorem IsOpenQuotientMap.prodMap {f : X → Y} {g : Z → W} (hf : IsOpenQuotie (hg : IsOpenQuotientMap g) : IsOpenQuotientMap (Prod.map f g) := ⟨.prodMap hf.1 hg.1, .prodMap hf.2 hg.2, .prodMap hf.3 hg.3⟩ +theorem isOpenMap_prodMap_iff [Nonempty X] [Nonempty Z] {f : X → Y} {g : Z → W} : + IsOpenMap (Prod.map f g) ↔ IsOpenMap f ∧ IsOpenMap g := by + refine ⟨fun h ↦ ⟨?_, ?_⟩, fun ⟨hf, hg⟩ ↦ hf.prodMap hg⟩ + · rw [(isOpenQuotientMap_fst (Y := Z)).isOpenMap_iff] + exact isOpenMap_fst.comp h + · rw [(isOpenQuotientMap_snd (X := X)).isOpenMap_iff] + exact isOpenMap_snd.comp h + theorem isOpenQuotientMap_prodMap_iff [Nonempty X] [Nonempty Z] {f : X → Y} {g : Z → W} : IsOpenQuotientMap (Prod.map f g) ↔ IsOpenQuotientMap f ∧ IsOpenQuotientMap g := by have : Nonempty Y := .map f inferInstance have : Nonempty W := .map g inferInstance - refine ⟨fun h ↦ ⟨?_, ?_⟩, fun ⟨hf, hg⟩ ↦ hf.prodMap hg⟩ - · rw [← (isOpenQuotientMap_fst (Y := Z)).of_comp_iff] - exact isOpenQuotientMap_fst.comp h - · rw [← (isOpenQuotientMap_snd (X := X)).of_comp_iff] - exact isOpenQuotientMap_snd.comp h + grind [isOpenQuotientMap_iff, continuous_prodMap_iff, isOpenMap_prodMap_iff, Prod.map_surjective] end Prod From ca646ce0bfe1fd5b3823dcce15645c0d9815f8b9 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 17 Jun 2026 00:49:56 +0200 Subject: [PATCH 122/210] nits --- .../Analysis/Normed/Operator/Perturbation/StrictByFinite.lean | 4 ++-- Mathlib/Topology/Maps/Strict/Basic.lean | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index c24b60f5a83c7f..7e0956f2a19c3b 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -89,7 +89,7 @@ theorem new_step1 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) · rw [codisjoint_iff, ← Submodule.map_sup, S_compl_A.sup_eq_top, Submodule.map_top, h_range] -- Because `A` (resp. `map u A`) is closed and `S` (resp `map u S`) is closed, `A` and `S` - -- (resp `map u A` and `map u A`) are in fact *topological* complements of each other. + -- (resp `map u A` and `map u S`) are in fact *topological* complements of each other. replace S_compl_A : IsTopCompl S A := S_compl_A.symm.isTopCompl_of_finiteDimensional_quotient A_closed |>.symm replace uS_compl_uA : IsTopCompl (map u.toLinearMap S) (map u.toLinearMap A) := @@ -110,7 +110,7 @@ theorem new_step1 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) ext x simp [Φ, Ψ, uₛ, uₐ, ← map_add, projection_add_projection_eq_self] have u_restr_eq : u.domRestrict A = (map u.toLinearMap A).subtypeL ∘ uₐ := rfl - suffices IsStrictMap (Prod.map uₛ uₐ) ↔ IsStrictMap uₐ by + suffices IsStrictMap (uₛ.prodMap uₐ) ↔ IsStrictMap uₐ by rw [u_restr_eq, u_eq, ← (isEmbedding_subtypeL _).isStrictMap_iff] sorry -- easy, missing API sorry -- easy, missing API diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index ce0b155a8da577..746be179789fdf 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -193,7 +193,7 @@ variable {f g} [TopologicalSpace G'] [IsTopologicalGroup G'] [TopologicalSpace H /-- The product (in the sense of `Prod.map`) of group homomorphisms is strict if and only if each of the morphisms is strict. -/ -@[to_additive] lemma isStrictMap_prodMap_iff : +@[to_additive isStrictMap_prodMap_iff] lemma isStrictMap_prodMap_iff : IsStrictMap (f.prodMap g) ↔ IsStrictMap f ∧ IsStrictMap g := by simp_rw [isStrictMap_iff_isOpenQuotientMap_rangeRestrict] let Φ : (f.prodMap g).range ≃ₜ f.range × g.range := From e977716058f10e2663bb5ef7974f6e9d17ca5be2 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 17 Jun 2026 14:10:42 +0200 Subject: [PATCH 123/210] Final touches (?) :tada: --- .../Operator/Perturbation/StrictByFinite.lean | 89 +++++++++++-------- .../Module/ContinuousLinearMap/Basic.lean | 13 ++- 2 files changed, 61 insertions(+), 41 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 7e0956f2a19c3b..103d46571462a1 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -9,6 +9,7 @@ public import Mathlib.RingTheory.Finiteness.Cofinite public import Mathlib.Topology.Maps.Strict.Basic public import Mathlib.Topology.LocalAtTarget public import Mathlib.Topology.Algebra.Module.FiniteDimension +public import Mathlib.Algebra.Module.LinearMap.FiniteRange /-! # Strict linear maps with closed range are closed under finite-rank perturbation @@ -69,7 +70,7 @@ We prove the theorem under the assumptions that - `map u A` is closed -/ -theorem new_step1 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) +theorem step1 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) (uA_closed : IsClosed (map u.toLinearMap A : Set F)) : @@ -104,6 +105,10 @@ theorem new_step1 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) set Φ : (S × A) ≃L[𝕜] E := prodEquivOfIsTopCompl S A S_compl_A set Ψ : (map u.toLinearMap S × map u.toLinearMap A) ≃L[𝕜] F := prodEquivOfIsTopCompl _ _ uS_compl_uA + -- TODO: after PR #39476 we will be able to use `Φ.symm.isHomeomorph` + have Φ_symm_homeo : IsHomeomorph Φ.symm := Φ.symm.toHomeomorph.isHomeomorph + -- TODO: after PR #39476 we will be able to use `Ψ.isHomeomorph` + have Ψ_homeo : IsHomeomorph Ψ := Ψ.toHomeomorph.isHomeomorph have uₛ_surj : Surjective uₛ := surjective_mapsTo_image_restrict _ _ have uₐ_surj : Surjective uₐ := surjective_mapsTo_image_restrict _ _ have u_eq : u = Ψ ∘ (uₛ.prodMap uₐ) ∘ Φ.symm := by @@ -111,9 +116,12 @@ theorem new_step1 (u : E →L[𝕜] F) (A : Submodule 𝕜 E) simp [Φ, Ψ, uₛ, uₐ, ← map_add, projection_add_projection_eq_self] have u_restr_eq : u.domRestrict A = (map u.toLinearMap A).subtypeL ∘ uₐ := rfl suffices IsStrictMap (uₛ.prodMap uₐ) ↔ IsStrictMap uₐ by - rw [u_restr_eq, u_eq, ← (isEmbedding_subtypeL _).isStrictMap_iff] - sorry -- easy, missing API - sorry -- easy, missing API + rwa [u_restr_eq, u_eq, ← (isEmbedding_subtypeL _).isStrictMap_iff, + ← Ψ_homeo.isEmbedding.isStrictMap_iff, ← Φ_symm_homeo.isQuotientMap.isStrictMap_iff] + -- TODO: we should think of a way to avoid this + change IsStrictMap (uₛ.toAddMonoidHom.prodMap uₐ.toAddMonoidHom) ↔ IsStrictMap uₐ + simp_rw [AddMonoidHom.isStrictMap_prodMap_iff, LinearMap.toAddMonoidHom_coe, coe_coe, + uₛ.isStrictMap_of_finiteDimensional, true_and] /-! ### Step 2 @@ -123,12 +131,12 @@ We prove the theorem under the assumptions that - `u.ker` is disjoint from `A` (i.e. `u` is injective on `A`) -/ -theorem new_step2 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) +theorem step2 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) : IsStrictMap u ↔ IsStrictMap (u.domRestrict A) ∧ IsClosed (map u.toLinearMap A : Set F) := by -- To reduce to step 1, it suffices to show that `IsStrictMap u → IsClosed (map u A)`. - suffices IsStrictMap u → IsClosed (map u.toLinearMap A : Set F) by grind only [new_step1] + suffices IsStrictMap u → IsClosed (map u.toLinearMap A : Set F) by grind only [step1] -- So, we assume that `u` is strict. Because it is surjective, it is a quotient map. intro u_strict have u_quot : IsQuotientMap u := by @@ -147,7 +155,7 @@ We prove the theorem under the assumptions that - `u.ker` is disjoint from `A` (i.e. `u` is injective on `A`) -/ -theorem new_step3 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) +theorem step3 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) (h_range : IsClosed (u.range : Set F)) : IsStrictMap u ↔ IsStrictMap (u.domRestrict A) ∧ IsClosed (map u.toLinearMap A : Set F) := by @@ -166,7 +174,7 @@ theorem new_step3 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) simp_rw [eq2, eq1, coe_comp, ← i_clemb.isEmbedding.isStrictMap_iff, toLinearMap_comp, map_comp, map_coe i.toLinearMap, coe_coe, ← i_clemb.isClosed_iff_image_isClosed] -- We finish by applying step 2 (using that `u.ker = u'.ker`). - exact new_step2 u' A A_closed (u.ker_rangeRestrict ▸ h_ker) range_u' + exact step2 u' A A_closed (u.ker_rangeRestrict ▸ h_ker) range_u' /-! ### Step 4 @@ -175,13 +183,13 @@ We prove the theorem under the assumption that `u.ker` is disjoint from `A` (i.e. `u` is injective on `A`). -/ -theorem new_step4 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) +theorem step4 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) : (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ IsStrictMap (u.domRestrict A) ∧ IsClosed (map u.toLinearMap A : Set F) := by -- To reduce to step 3, it suffices to show that, if `map u A` is closed, then so is `u.range`. suffices IsClosed (map u.toLinearMap A : Set F) → IsClosed (u.range : Set F) by - grind only [new_step3] + grind only [step3] -- So, we assume that `map u A` is closed. intro uA_closed -- Fix `S` an algebraic complement of `A` containing `u.ker`. It has finite dimension. @@ -209,7 +217,7 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Sp [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] : (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ (IsStrictMap (u.domRestrict A) ∧ IsClosed (map u.toLinearMap A : Set F)) := by - -- To reduce to step 2, we quotient by `N := A ⊓ u.ker`. Denoting by `π : E → E ⧸ N` + -- To reduce to step 4, we quotient by `N := A ⊓ u.ker`. Denoting by `π : E → E ⧸ N` -- the (automatically open) quotient map, `u` factors as `v ∘ π` with `v : E ⧸ N → F`. set N : Submodule 𝕜 E := A ⊓ u.ker set π : E →L[𝕜] E ⧸ N := N.mkQL @@ -233,9 +241,9 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Sp rwa [← π_quot.isQuotientMap.isClosed_preimage, ← π.coe_coe, ← comap_coe, comap_B] -- Thus, we can apply step 4 to `v`: we get that `v` is strict with closed range if -- and only if `v.domRestrict B` is strict with closed range. - have step3_output : (IsStrictMap v ∧ IsClosed (v.range : Set F)) ↔ + have step4_output : (IsStrictMap v ∧ IsClosed (v.range : Set F)) ↔ (IsStrictMap (v.domRestrict B) ∧ IsClosed (map v.toLinearMap B : Set F)) := by - simp [new_step4 v B B_closed v_ker, coe_domRestrict, ← range_restrict] + simp [step4 v B B_closed v_ker, coe_domRestrict, ← range_restrict] -- Now, we wish to reduce our statement about `u` and `u.domRestrict A` -- to what we know about `v` and `v.domRestrict B`. -- First, it is clear that `range u = range v` and `map u A = map v B`. @@ -260,12 +268,19 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Sp rw [← v_comp_π'_eq_u, coe_comp, ← π'_quot.isQuotientMap.isStrictMap_iff] -- Thus, we are done! rw [strict_iff, strict_iff_restrict, ← range_eq, ← image_eq] - exact step3_output + exact step4_output + +end FiniteCodimSubspace + +/-! +## Consequences +-/ + +section FiniteRank --- TODO: state in terms of "equality modulo finite rank" relation /-- If `u, v : E →L[𝕜] F` agree on a closed subspace `A` of `E` with finite codimension, then `u` is strict with closed range if and only if `v` is strict with closed range. -/ -public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_eqOn [T1Space F] +public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_eqOn [T2Space F] (u v : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_eqOn : EqOn u v A) : (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ @@ -275,34 +290,28 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_eqOn [T1Spa LinearMap.coe_range, LinearMap.coe_domRestrict, ContinuousLinearMap.coe_domRestrict, ContinuousLinearMap.coe_coe, restrict_eq_restrict_iff.mpr h_eqOn] -end FiniteCodimSubspace - -/-! -## Consequences --/ - -section FiniteRank +open LinearMap.FiniteRangeSetoid --- TODO: state in terms of "equality modulo finite rank" relation --- TODO: unify with statement above -/-- If `u, v : E →L[𝕜] F` differ by a finite rank continuous linear map, then `u` is strict with -closed range if and only if `v` is strict with closed range. +/-- If `u, v : E →L[𝕜] F` differ by a finite rank continuous linear map (recall that this is +denoted `u.toLinearMap ≈ v.toLinearMap` in scope `LinearMap.FiniteRangeSetoid`), then `u` is +strict with closed range if and only if `v` is strict with closed range. This is [N. Bourbaki, *Théories Spectrales*, Chapitre III, § 3, n° 1, Cor. 1][bourbaki2023]. -/ -public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_finiteDimensional [T1Space F] - (u v : E →L[𝕜] F) (h_finite_rank : FiniteDimensional 𝕜 (u - v).range) : +public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_finiteRangeSetoid [T1Space F] + (u v : E →L[𝕜] F) (h_equiv : u.toLinearMap ≈ v.toLinearMap) : (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ (IsStrictMap v ∧ IsClosed (v.range : Set F)) := by - let A := (u - v).ker - have A_closed : IsClosed (A : Set E) := (u - v).isClosed_ker - have : FiniteDimensional 𝕜 (E ⧸ A) := (u - v).toLinearMap.quotKerEquivRange.symm.finiteDimensional - have eqOn_A : EqOn u v A := fun _ ↦ by simp [A, sub_eq_zero] - exact ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_eqOn u v A A_closed eqOn_A + let A := u.toLinearMap.eqLocus v.toLinearMap + have A_closed : IsClosed (A : Set E) := u.isClosed_eqLocus v + have : FiniteDimensional 𝕜 (E ⧸ A) := equiv_iff_eqLocus_coFG.mp h_equiv + exact ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_eqOn u v A A_closed (fun _ ↦ id) end FiniteRank section FiniteDimQuotient +open LinearMap.FiniteRangeSetoid + /-- Consider `u : E →L[𝕜] F` and `B` a *complemented* finite dimensional subspace `F`. We have that `u` is strict with closed range if and only if `B.mkQL ∘L u` is strict with closed range. @@ -318,13 +327,15 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_quotient [T1Sp have i_clemb : IsClosedEmbedding i := S.isClosedEmbedding_subtypeL A_compl_S.symm.isClosed let p : F →L[𝕜] F := S.projectionL A A_compl_S.symm have eq : i ∘ Φ ∘ A.mkQ = p := rfl - have : FiniteDimensional 𝕜 (u - p ∘L u).range := by - suffices (u - p ∘L u).range ≤ A from finiteDimensional_of_le this - rintro - ⟨x, rfl⟩ - exact sub_projection_mem _ (u x) + -- TODO: The following should be extracted to API about `≈`. + have : .id ≈ p.toLinearMap := by + simp [equiv_iff_hasFiniteRange, p, ← projection_eq_id_sub_projection, LinearMap.HasFiniteRange, + fg_iff_finiteDimensional, dim_A] + have : u.toLinearMap ≈ (p ∘L u).toLinearMap := by + grw [toLinearMap_comp, ← this, LinearMap.id_comp] calc IsStrictMap u ∧ IsClosed (range u) _ ↔ (IsStrictMap (p ∘ u) ∧ IsClosed (range (p ∘ u))) := - ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_finiteDimensional _ _ this + ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_finiteRangeSetoid _ _ this _ ↔ (IsStrictMap (i ∘ Φ ∘ A.mkQ ∘ u) ∧ IsClosed (range (i ∘ Φ ∘ A.mkQ ∘ u))) := by simp_rw [← eq, Function.comp_assoc] _ ↔ (IsStrictMap (Φ ∘ A.mkQ ∘ u) ∧ IsClosed (range (Φ ∘ A.mkQ ∘ u))) := by diff --git a/Mathlib/Topology/Algebra/Module/ContinuousLinearMap/Basic.lean b/Mathlib/Topology/Algebra/Module/ContinuousLinearMap/Basic.lean index bbe7c8ee90e94e..f0f7d0b1425042 100644 --- a/Mathlib/Topology/Algebra/Module/ContinuousLinearMap/Basic.lean +++ b/Mathlib/Topology/Algebra/Module/ContinuousLinearMap/Basic.lean @@ -686,13 +686,22 @@ end ApplyAction theorem isClosed_ker [T1Space M₂] (f : M₁ →SL[σ₁₂] M₂) : IsClosed (f.ker : Set M₁) := - continuous_iff_isClosed.1 (map_continuous f) _ isClosed_singleton + isClosed_singleton.preimage f.continuous + +theorem isClosed_eqLocus [T2Space M₂] (f g : M₁ →SL[σ₁₂] M₂) : + IsClosed (f.eqLocus g : Set M₁) := + isClosed_eq f.continuous g.continuous theorem isComplete_ker {M' : Type*} [UniformSpace M'] [CompleteSpace M'] [AddCommMonoid M'] [Module R₁ M'] [T1Space M₂] (f : M' →SL[σ₁₂] M₂) : IsComplete (f.ker : Set M') := (isClosed_ker f).isComplete +theorem isComplete_eqLocus {M' : Type*} [UniformSpace M'] [CompleteSpace M'] [AddCommMonoid M'] + [Module R₁ M'] [T2Space M₂] (f g : M' →SL[σ₁₂] M₂) : + IsComplete (f.eqLocus g : Set M') := + (isClosed_eqLocus f g).isComplete + instance completeSpace_ker {M' : Type*} [UniformSpace M'] [CompleteSpace M'] [AddCommMonoid M'] [Module R₁ M'] [T1Space M₂] (f : M' →SL[σ₁₂] M₂) : CompleteSpace f.ker := @@ -701,7 +710,7 @@ instance completeSpace_ker {M' : Type*} [UniformSpace M'] [CompleteSpace M'] instance completeSpace_eqLocus {M' : Type*} [UniformSpace M'] [CompleteSpace M'] [AddCommMonoid M'] [Module R₁ M'] [T2Space M₂] (f g : M' →SL[σ₁₂] M₂) : CompleteSpace (f.toLinearMap.eqLocus g.toLinearMap) := - IsClosed.completeSpace_coe (hs := isClosed_eq (map_continuous f) (map_continuous g)) + (isComplete_eqLocus f g).completeSpace_coe section From 9e672df5b828688bccdcec627b1a4756a8ee475f Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 17 Jun 2026 14:21:23 +0200 Subject: [PATCH 124/210] missing comment --- .../Analysis/Normed/Operator/Perturbation/StrictByFinite.lean | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 103d46571462a1..f2d90890c7d88e 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -102,6 +102,8 @@ theorem step1 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) -- Using the corresponding isomorphisms `(S × A) ≃L[𝕜] E` and `(map u S × map u A) ≃L[𝕜] F`, -- we have to show that the map `uₛ.prodMap uₐ : S × A → map u S × map u A` is strict -- if and only if `uₐ : A → map u A` is strict. + -- This follows from `AddMonoidHom.isStrictMap_prodMap_iff`, and the fact that `uₛ` is a + -- continuous linear map between finite dimensional spaces, hence a strict map. set Φ : (S × A) ≃L[𝕜] E := prodEquivOfIsTopCompl S A S_compl_A set Ψ : (map u.toLinearMap S × map u.toLinearMap A) ≃L[𝕜] F := prodEquivOfIsTopCompl _ _ uS_compl_uA From 1913f0e5b00ac7385a3d949483313e2cfa485579 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 17 Jun 2026 14:39:04 +0200 Subject: [PATCH 125/210] start --- Mathlib/Topology/Constructions/SumProd.lean | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Mathlib/Topology/Constructions/SumProd.lean b/Mathlib/Topology/Constructions/SumProd.lean index 8c417843dbf7e1..77c5b8d37ac4fb 100644 --- a/Mathlib/Topology/Constructions/SumProd.lean +++ b/Mathlib/Topology/Constructions/SumProd.lean @@ -358,6 +358,14 @@ theorem ContinuousAt.prodMap' {f : X → Z} {g : Y → W} {x : X} {y : Y} (hf : (hg : ContinuousAt g y) : ContinuousAt (Prod.map f g) (x, y) := hf.prodMap hg +theorem continuousAt_prodMap_iff [Nonempty X] [Nonempty Y] {f : X → Z} {g : Y → W} {x : X} {y : Y} : + ContinuousAt (Prod.map f g) (x, y) ↔ ContinuousAt f x ∧ ContinuousAt g y := by + simp [ContinuousAt, nhds_prod_eq, tendsto_iff_comap, comap_prodMap_prod] + +theorem continuous_prodMap_iff [Nonempty Z] [Nonempty W] {f : Z → X} {g : W → Y} : + Continuous (Prod.map f g) ↔ Continuous f ∧ Continuous g := by + simp [continuous_iff_continuousAt, continuousAt_prodMap_iff, forall_and] + theorem ContinuousAt.comp₂ {f : Y × Z → W} {g : X → Y} {h : X → Z} {x : X} (hf : ContinuousAt f (g x, h x)) (hg : ContinuousAt g x) (hh : ContinuousAt h x) : ContinuousAt (fun x ↦ f (g x, h x)) x := @@ -494,12 +502,6 @@ theorem isOpen_prod_iff' {s : Set X} {t : Set Y} : simp only [st.1.ne_empty, st.2.ne_empty, or_false] at H exact H.1.prod H.2 -theorem isQuotientMap_fst [Nonempty Y] : IsQuotientMap (Prod.fst : X × Y → X) := - isOpenMap_fst.isQuotientMap continuous_fst Prod.fst_surjective - -theorem isQuotientMap_snd [Nonempty X] : IsQuotientMap (Prod.snd : X × Y → Y) := - isOpenMap_snd.isQuotientMap continuous_snd Prod.snd_surjective - theorem closure_prod_eq {s : Set X} {t : Set Y} : closure (s ×ˢ t) = closure s ×ˢ closure t := ext fun ⟨a, b⟩ => by simp_rw [mem_prod, mem_closure_iff_nhdsWithin_neBot, nhdsWithin_prod_eq, prod_neBot] @@ -608,10 +610,6 @@ lemma isEmbedding_prodMkLeft (y : Y) : IsEmbedding (fun x : X ↦ (x, y)) := lemma isEmbedding_prodMkRight (x : X) : IsEmbedding (Prod.mk x : Y → X × Y) := .of_comp (.prodMk_right x) continuous_snd .id -theorem IsOpenQuotientMap.prodMap {f : X → Y} {g : Z → W} (hf : IsOpenQuotientMap f) - (hg : IsOpenQuotientMap g) : IsOpenQuotientMap (Prod.map f g) := - ⟨.prodMap hf.1 hg.1, .prodMap hf.2 hg.2, .prodMap hf.3 hg.3⟩ - theorem TopologicalSpace.prod_mono {α β : Type*} {σ₁ σ₂ : TopologicalSpace α} {τ₁ τ₂ : TopologicalSpace β} (hσ : σ₁ ≤ σ₂) (hτ : τ₁ ≤ τ₂) : @instTopologicalSpaceProd α β σ₁ τ₁ ≤ @instTopologicalSpaceProd α β σ₂ τ₂ := From 791c085ae2e40f688e6277343ebb8a2cb18cb628 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 17 Jun 2026 14:43:09 +0200 Subject: [PATCH 126/210] chore: move `IsOpenQuotientMap.baireSpace` to `Baire.Lemmas`. --- Mathlib/Topology/Baire/Lemmas.lean | 12 +++++++++++- Mathlib/Topology/Maps/OpenQuotient.lean | 10 ---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Mathlib/Topology/Baire/Lemmas.lean b/Mathlib/Topology/Baire/Lemmas.lean index 0f15e154154f65..7d9c592d303eeb 100644 --- a/Mathlib/Topology/Baire/Lemmas.lean +++ b/Mathlib/Topology/Baire/Lemmas.lean @@ -6,8 +6,9 @@ Authors: Sébastien Gouëzel module public import Mathlib.Data.Fintype.Powerset -public import Mathlib.Topology.GDelta.Basic public import Mathlib.Topology.Constructions +public import Mathlib.Topology.GDelta.Basic +public import Mathlib.Topology.Maps.OpenQuotient public import Mathlib.Tactic.CrossRefAttribute /-! @@ -111,6 +112,15 @@ theorem Topology.IsOpenEmbedding.baireSpace {Y : Type*} [TopologicalSpace Y] {p theorem IsOpen.baireSpace {s : Set X} (hO : IsOpen s) : BaireSpace s := hO.isOpenEmbedding_subtypeVal.baireSpace +/-- If `f` is an open quotient map and `X` is Baire, then `Y` is Baire. -/ +theorem IsOpenQuotientMap.baireSpace {Y : Type*} [TopologicalSpace Y] {f : X → Y} + (hf : IsOpenQuotientMap f) : BaireSpace Y := by + constructor + intro u hou hdu + have := dense_iInter_of_isOpen_nat (fun n => hf.continuous.isOpen_preimage (u n) (hou n)) + (fun n => (IsOpenQuotientMap.dense_preimage_iff hf).mpr (hdu n)) + simp_all [← preimage_iInter, IsOpenQuotientMap.dense_preimage_iff] + /-- Baire theorem: a countable intersection of dense open sets is dense. Formulated here with ⋂₀. -/ theorem dense_sInter_of_isOpen {S : Set (Set X)} (ho : ∀ s ∈ S, IsOpen s) (hS : S.Countable) (hd : ∀ s ∈ S, Dense s) : Dense (⋂₀ S) := by diff --git a/Mathlib/Topology/Maps/OpenQuotient.lean b/Mathlib/Topology/Maps/OpenQuotient.lean index ccbd3c06193cac..be2ce3cb93e7f3 100644 --- a/Mathlib/Topology/Maps/OpenQuotient.lean +++ b/Mathlib/Topology/Maps/OpenQuotient.lean @@ -6,7 +6,6 @@ Authors: Yury Kudryashov module public import Mathlib.Topology.Maps.Basic -public import Mathlib.Topology.Baire.Lemmas /-! # Open quotient maps @@ -65,15 +64,6 @@ theorem dense_preimage_iff (h : IsOpenQuotientMap f) {s : Set Y} : Dense (f ⁻ ⟨fun hs ↦ h.surjective.denseRange.dense_of_mapsTo h.continuous hs (mapsTo_preimage _ _), fun hs ↦ hs.preimage h.isOpenMap⟩ -/-- If `f` is an open quotient map and `X` is Baire, then `Y` is Baire. -/ -theorem baireSpace {f : X → Y} [BaireSpace X] (hf : IsOpenQuotientMap f) : - BaireSpace Y := by - constructor - intro u hou hdu - have := dense_iInter_of_isOpen_nat (fun n => hf.continuous.isOpen_preimage (u n) (hou n)) - (fun n => (IsOpenQuotientMap.dense_preimage_iff hf).mpr (hdu n)) - simp_all [← preimage_iInter, IsOpenQuotientMap.dense_preimage_iff] - end IsOpenQuotientMap theorem Topology.IsInducing.isOpenQuotientMap_of_surjective (ind : IsInducing f) From dc6126f112d197766462ece0c3e1eb41274f1159 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 17 Jun 2026 14:55:27 +0200 Subject: [PATCH 127/210] feat: a few misc results about open (quotient) maps --- Mathlib/Topology/Constructions/SumProd.lean | 32 ++++++++++++++++++++- Mathlib/Topology/Homeomorph/Defs.lean | 16 ++++++++++- Mathlib/Topology/Maps/Basic.lean | 6 ++++ Mathlib/Topology/Maps/OpenQuotient.lean | 13 +++++++++ 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/Mathlib/Topology/Constructions/SumProd.lean b/Mathlib/Topology/Constructions/SumProd.lean index 77c5b8d37ac4fb..c93aab32b48cea 100644 --- a/Mathlib/Topology/Constructions/SumProd.lean +++ b/Mathlib/Topology/Constructions/SumProd.lean @@ -6,7 +6,7 @@ Authors: Johannes Hölzl, Mario Carneiro, Patrick Massot module public import Mathlib.Topology.Homeomorph.Defs -public import Mathlib.Topology.Maps.Basic +public import Mathlib.Topology.Maps.OpenQuotient public import Mathlib.Topology.Separation.SeparatedNhds /-! @@ -502,6 +502,18 @@ theorem isOpen_prod_iff' {s : Set X} {t : Set Y} : simp only [st.1.ne_empty, st.2.ne_empty, or_false] at H exact H.1.prod H.2 +theorem isOpenQuotientMap_fst [Nonempty Y] : IsOpenQuotientMap (Prod.fst : X × Y → X) := + ⟨Prod.fst_surjective, continuous_fst, isOpenMap_fst⟩ + +theorem isOpenQuotientMap_snd [Nonempty X] : IsOpenQuotientMap (Prod.snd : X × Y → Y) := + ⟨Prod.snd_surjective, continuous_snd, isOpenMap_snd⟩ + +theorem isQuotientMap_fst [Nonempty Y] : IsQuotientMap (Prod.fst : X × Y → X) := + isOpenQuotientMap_fst.isQuotientMap + +theorem isQuotientMap_snd [Nonempty X] : IsQuotientMap (Prod.snd : X × Y → Y) := + isOpenQuotientMap_snd.isQuotientMap + theorem closure_prod_eq {s : Set X} {t : Set Y} : closure (s ×ˢ t) = closure s ×ˢ closure t := ext fun ⟨a, b⟩ => by simp_rw [mem_prod, mem_closure_iff_nhdsWithin_neBot, nhdsWithin_prod_eq, prod_neBot] @@ -591,6 +603,14 @@ protected theorem IsOpenMap.prodMap {f : X → Y} {g : Z → W} (hf : IsOpenMap rw [nhds_prod_eq, nhds_prod_eq, ← Filter.prod_map_map_eq'] exact Filter.prod_mono (hf.nhds_le a) (hg.nhds_le b) +theorem isOpenMap_prodMap_iff [Nonempty X] [Nonempty Z] {f : X → Y} {g : Z → W} : + IsOpenMap (Prod.map f g) ↔ IsOpenMap f ∧ IsOpenMap g := by + refine ⟨fun h ↦ ⟨?_, ?_⟩, fun ⟨hf, hg⟩ ↦ hf.prodMap hg⟩ + · rw [(isOpenQuotientMap_fst (Y := Z)).isOpenMap_iff] + exact isOpenMap_fst.comp h + · rw [(isOpenQuotientMap_snd (X := X)).isOpenMap_iff] + exact isOpenMap_snd.comp h + protected lemma Topology.IsOpenEmbedding.prodMap {f : X → Y} {g : Z → W} (hf : IsOpenEmbedding f) (hg : IsOpenEmbedding g) : IsOpenEmbedding (Prod.map f g) := .of_isEmbedding_isOpenMap (hf.1.prodMap hg.1) (hf.isOpenMap.prodMap hg.isOpenMap) @@ -615,6 +635,16 @@ theorem TopologicalSpace.prod_mono {α β : Type*} {σ₁ σ₂ : TopologicalSpa @instTopologicalSpaceProd α β σ₁ τ₁ ≤ @instTopologicalSpaceProd α β σ₂ τ₂ := le_inf (inf_le_left.trans <| induced_mono hσ) (inf_le_right.trans <| induced_mono hτ) +theorem IsOpenQuotientMap.prodMap {f : X → Y} {g : Z → W} (hf : IsOpenQuotientMap f) + (hg : IsOpenQuotientMap g) : IsOpenQuotientMap (Prod.map f g) := + ⟨.prodMap hf.1 hg.1, .prodMap hf.2 hg.2, .prodMap hf.3 hg.3⟩ + +theorem isOpenQuotientMap_prodMap_iff [Nonempty X] [Nonempty Z] {f : X → Y} {g : Z → W} : + IsOpenQuotientMap (Prod.map f g) ↔ IsOpenQuotientMap f ∧ IsOpenQuotientMap g := by + have : Nonempty Y := .map f inferInstance + have : Nonempty W := .map g inferInstance + grind [isOpenQuotientMap_iff, continuous_prodMap_iff, isOpenMap_prodMap_iff, Prod.map_surjective] + -- Homeomorphisms between the various product: products of two homeomorphisms, -- as well as commutativity and associativity. See below for the analogous results for sums, -- as well as distributivity, etc. diff --git a/Mathlib/Topology/Homeomorph/Defs.lean b/Mathlib/Topology/Homeomorph/Defs.lean index 79ccff73ceae30..2833bea0f96d53 100644 --- a/Mathlib/Topology/Homeomorph/Defs.lean +++ b/Mathlib/Topology/Homeomorph/Defs.lean @@ -6,7 +6,7 @@ Authors: Johannes Hölzl, Patrick Massot, Sébastien Gouëzel, Zhouhang Zhou, Re module public import Mathlib.Topology.ContinuousMap.Defs -public import Mathlib.Topology.Maps.Basic +public import Mathlib.Topology.Maps.OpenQuotient /-! # Homeomorphisms @@ -342,6 +342,20 @@ theorem comp_isOpenMap_iff' (h : X ≃ₜ Y) {f : Y → Z} : IsOpenMap (f ∘ h) rw [← Function.comp_id f, ← h.self_comp_symm, ← Function.comp_assoc] exact hf.comp h.symm.isOpenMap +/-- Open quotient maps are preserved by precomposing with a homeomorphism. -/ +@[simp] +theorem isOpenQuotient_comp_iff (e : X ≃ₜ Y) {f : Y → Z} : + IsOpenQuotientMap (f ∘ e) ↔ IsOpenQuotientMap f := + ⟨fun h ↦ by simpa [Function.comp_assoc] using h.comp e.symm.isOpenQuotientMap, + fun hf ↦ hf.comp e.isOpenQuotientMap⟩ + +/-- Open quotient maps are preserved by postcomposing with a homeomorphism. -/ +@[simp] +theorem comp_isOpenQuotientMap_iff (e : Y ≃ₜ Z) {f : X → Y} : + IsOpenQuotientMap (e ∘ f) ↔ IsOpenQuotientMap f := + ⟨fun h ↦ by simpa [← Function.comp_assoc] using e.symm.isOpenQuotientMap.comp h, + fun hf ↦ e.isOpenQuotientMap.comp hf⟩ + variable (X Y) in /-- If both `X` and `Y` have a unique element, then `X ≃ₜ Y`. -/ @[simps!] diff --git a/Mathlib/Topology/Maps/Basic.lean b/Mathlib/Topology/Maps/Basic.lean index c5f7c9ca50bb24..4efc1e7e0b3e4e 100644 --- a/Mathlib/Topology/Maps/Basic.lean +++ b/Mathlib/Topology/Maps/Basic.lean @@ -369,6 +369,12 @@ protected theorem id : IsOpenMap (@id X) := fun s hs => by rwa [image_id] protected theorem comp (hg : IsOpenMap g) (hf : IsOpenMap f) : IsOpenMap (g ∘ f) := fun s hs => by rw [image_comp]; exact hg _ (hf _ hs) +/-- If `g ∘ f` is open, where `f` is continuous and surjective, then `g` is open. -/ +theorem of_comp (hf : Continuous f) (f_surj : Surjective f) (h : IsOpenMap (g ∘ f)) : + IsOpenMap g := fun s hs => by + rw [← f_surj.image_preimage s, ← image_comp] + exact h _ (hs.preimage hf) + theorem isOpen_range (hf : IsOpenMap f) : IsOpen (range f) := by rw [← image_univ] exact hf _ isOpen_univ diff --git a/Mathlib/Topology/Maps/OpenQuotient.lean b/Mathlib/Topology/Maps/OpenQuotient.lean index be2ce3cb93e7f3..139d7c8ec14f05 100644 --- a/Mathlib/Topology/Maps/OpenQuotient.lean +++ b/Mathlib/Topology/Maps/OpenQuotient.lean @@ -49,6 +49,15 @@ theorem comp {g : Y → Z} (hg : IsOpenQuotientMap g) (hf : IsOpenQuotientMap f) IsOpenQuotientMap (g ∘ f) := ⟨.comp hg.1 hf.1, .comp hg.2 hf.2, .comp hg.3 hf.3⟩ +theorem of_comp {g : Y → Z} (hf : Continuous f) (f_surj : Surjective f) (hg : Continuous g) + (h : IsOpenQuotientMap (g ∘ f)) : IsOpenQuotientMap g := + ⟨.of_comp h.surjective, hg, .of_comp hf f_surj h.isOpenMap ⟩ + +theorem of_comp_iff {g : Y → Z} (hf : IsOpenQuotientMap f) : + IsOpenQuotientMap (g ∘ f) ↔ IsOpenQuotientMap g := + ⟨fun h ↦ .of_comp hf.continuous hf.surjective + (hf.isQuotientMap.continuous_iff.mpr h.continuous) h, fun hg ↦ hg.comp hf⟩ + theorem map_nhds_eq (h : IsOpenQuotientMap f) (x : X) : map f (𝓝 x) = 𝓝 (f x) := le_antisymm h.continuous.continuousAt <| h.isOpenMap.nhds_le _ @@ -60,6 +69,10 @@ theorem continuousAt_comp_iff (h : IsOpenQuotientMap f) {g : Y → Z} {x : X} : ContinuousAt (g ∘ f) x ↔ ContinuousAt g (f x) := by simp only [ContinuousAt, ← h.map_nhds_eq, tendsto_map'_iff, comp_def] +theorem isOpenMap_iff (hf : IsOpenQuotientMap f) {g : Y → Z} : + IsOpenMap g ↔ IsOpenMap (g ∘ f) := + ⟨fun hg ↦ hg.comp hf.isOpenMap, fun h ↦ .of_comp hf.continuous hf.surjective h⟩ + theorem dense_preimage_iff (h : IsOpenQuotientMap f) {s : Set Y} : Dense (f ⁻¹' s) ↔ Dense s := ⟨fun hs ↦ h.surjective.denseRange.dense_of_mapsTo h.continuous hs (mapsTo_preimage _ _), fun hs ↦ hs.preimage h.isOpenMap⟩ From c1dcc9b994f9ca588e13ea4ccfca00759b368102 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 17 Jun 2026 15:00:50 +0200 Subject: [PATCH 128/210] more moving --- Mathlib/Topology/Baire/Lemmas.lean | 4 ++++ Mathlib/Topology/Homeomorph/Lemmas.lean | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Mathlib/Topology/Baire/Lemmas.lean b/Mathlib/Topology/Baire/Lemmas.lean index 7d9c592d303eeb..44abda6d1ad074 100644 --- a/Mathlib/Topology/Baire/Lemmas.lean +++ b/Mathlib/Topology/Baire/Lemmas.lean @@ -121,6 +121,10 @@ theorem IsOpenQuotientMap.baireSpace {Y : Type*} [TopologicalSpace Y] {f : X → (fun n => (IsOpenQuotientMap.dense_preimage_iff hf).mpr (hdu n)) simp_all [← preimage_iInter, IsOpenQuotientMap.dense_preimage_iff] +protected theorem Homeomorph.baireSpace {Y : Type*} [TopologicalSpace Y] (f : X ≃ₜ Y) : + BaireSpace Y := + f.isOpenQuotientMap.baireSpace + /-- Baire theorem: a countable intersection of dense open sets is dense. Formulated here with ⋂₀. -/ theorem dense_sInter_of_isOpen {S : Set (Set X)} (ho : ∀ s ∈ S, IsOpen s) (hS : S.Countable) (hd : ∀ s ∈ S, Dense s) : Dense (⋂₀ S) := by diff --git a/Mathlib/Topology/Homeomorph/Lemmas.lean b/Mathlib/Topology/Homeomorph/Lemmas.lean index 9fc328a54765e0..af989e2ee327c1 100644 --- a/Mathlib/Topology/Homeomorph/Lemmas.lean +++ b/Mathlib/Topology/Homeomorph/Lemmas.lean @@ -37,9 +37,6 @@ protected theorem secondCountableTopology [SecondCountableTopology Y] (h : X ≃ₜ Y) : SecondCountableTopology X := h.isInducing.secondCountableTopology -protected theorem baireSpace [BaireSpace X] (f : X ≃ₜ Y) : BaireSpace Y := - f.isOpenQuotientMap.baireSpace - /-- If `h : X → Y` is a homeomorphism, `h(s)` is compact iff `s` is. -/ @[simp] theorem isCompact_image {s : Set X} (h : X ≃ₜ Y) : IsCompact (h '' s) ↔ IsCompact s := From 004162494cfc4f41bc9c67ac0a7470c1e4419915 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 17 Jun 2026 15:03:24 +0200 Subject: [PATCH 129/210] better --- Mathlib/Topology/Baire/Lemmas.lean | 4 ---- Mathlib/Topology/Homeomorph/Lemmas.lean | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Mathlib/Topology/Baire/Lemmas.lean b/Mathlib/Topology/Baire/Lemmas.lean index 44abda6d1ad074..7d9c592d303eeb 100644 --- a/Mathlib/Topology/Baire/Lemmas.lean +++ b/Mathlib/Topology/Baire/Lemmas.lean @@ -121,10 +121,6 @@ theorem IsOpenQuotientMap.baireSpace {Y : Type*} [TopologicalSpace Y] {f : X → (fun n => (IsOpenQuotientMap.dense_preimage_iff hf).mpr (hdu n)) simp_all [← preimage_iInter, IsOpenQuotientMap.dense_preimage_iff] -protected theorem Homeomorph.baireSpace {Y : Type*} [TopologicalSpace Y] (f : X ≃ₜ Y) : - BaireSpace Y := - f.isOpenQuotientMap.baireSpace - /-- Baire theorem: a countable intersection of dense open sets is dense. Formulated here with ⋂₀. -/ theorem dense_sInter_of_isOpen {S : Set (Set X)} (ho : ∀ s ∈ S, IsOpen s) (hS : S.Countable) (hd : ∀ s ∈ S, Dense s) : Dense (⋂₀ S) := by diff --git a/Mathlib/Topology/Homeomorph/Lemmas.lean b/Mathlib/Topology/Homeomorph/Lemmas.lean index af989e2ee327c1..1dbcf2a6d5059b 100644 --- a/Mathlib/Topology/Homeomorph/Lemmas.lean +++ b/Mathlib/Topology/Homeomorph/Lemmas.lean @@ -9,6 +9,7 @@ public import Mathlib.Logic.Equiv.Fin.Basic public import Mathlib.Topology.Connected.LocallyConnected public import Mathlib.Topology.DenseEmbedding public import Mathlib.Topology.Connected.TotallyDisconnected +public import Mathlib.Topology.Baire.Lemmas /-! # Further properties of homeomorphisms @@ -37,6 +38,9 @@ protected theorem secondCountableTopology [SecondCountableTopology Y] (h : X ≃ₜ Y) : SecondCountableTopology X := h.isInducing.secondCountableTopology +protected theorem baireSpace [BaireSpace X] (f : X ≃ₜ Y) : BaireSpace Y := + f.isOpenQuotientMap.baireSpace + /-- If `h : X → Y` is a homeomorphism, `h(s)` is compact iff `s` is. -/ @[simp] theorem isCompact_image {s : Set X} (h : X ≃ₜ Y) : IsCompact (h '' s) ↔ IsCompact s := From 81865de5065660a019276440c04a7fa48df9cc0d Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 17 Jun 2026 15:04:41 +0200 Subject: [PATCH 130/210] fixed ? --- Mathlib/Topology/Order/IsLUB.lean | 1 + 1 file changed, 1 insertion(+) diff --git a/Mathlib/Topology/Order/IsLUB.lean b/Mathlib/Topology/Order/IsLUB.lean index 3780b512cae029..f36797e4ef2d73 100644 --- a/Mathlib/Topology/Order/IsLUB.lean +++ b/Mathlib/Topology/Order/IsLUB.lean @@ -5,6 +5,7 @@ Authors: Johannes Hölzl, Mario Carneiro, Yury Kudryashov -/ module +public import Mathlib.Order.Filter.CountableInter public import Mathlib.Topology.Order.LeftRightNhds /-! From b17bbba08ea671372bbb475644fd87cd4a211704 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 17 Jun 2026 15:11:07 +0200 Subject: [PATCH 131/210] fixes --- Mathlib/Topology/Constructions/SumProd.lean | 5 --- Mathlib/Topology/Maps/OpenQuotient.lean | 46 --------------------- 2 files changed, 51 deletions(-) diff --git a/Mathlib/Topology/Constructions/SumProd.lean b/Mathlib/Topology/Constructions/SumProd.lean index fd73f1537e7b7f..c93aab32b48cea 100644 --- a/Mathlib/Topology/Constructions/SumProd.lean +++ b/Mathlib/Topology/Constructions/SumProd.lean @@ -377,11 +377,6 @@ theorem ContinuousAt.comp₂_of_eq {f : Y × Z → W} {g : X → Y} {h : X → Z rw [← e] at hf exact hf.comp₂ hg hh -theorem continuous_prodMap_iff [Nonempty Z] [Nonempty W] {f : Z → X} {g : W → Y} : - Continuous (Prod.map f g) ↔ Continuous f ∧ Continuous g := by - simp [continuous_iff_continuousAt, ContinuousAt, nhds_prod_eq, tendsto_iff_comap, - comap_prodMap_prod, forall_and] - /-- Continuous functions on products are continuous in their first argument -/ theorem Continuous.curry_left {f : X × Y → Z} (hf : Continuous f) {y : Y} : Continuous fun x ↦ f (x, y) := diff --git a/Mathlib/Topology/Maps/OpenQuotient.lean b/Mathlib/Topology/Maps/OpenQuotient.lean index d4d99ef5505bd1..d6b4d32b35ddca 100644 --- a/Mathlib/Topology/Maps/OpenQuotient.lean +++ b/Mathlib/Topology/Maps/OpenQuotient.lean @@ -80,52 +80,6 @@ theorem dense_preimage_iff (h : IsOpenQuotientMap f) {s : Set Y} : Dense (f ⁻ end IsOpenQuotientMap -section Prod - -theorem isOpenQuotientMap_fst [Nonempty Y] : IsOpenQuotientMap (Prod.fst : X × Y → X) := - ⟨Prod.fst_surjective, continuous_fst, isOpenMap_fst⟩ - -theorem isOpenQuotientMap_snd [Nonempty X] : IsOpenQuotientMap (Prod.snd : X × Y → Y) := - ⟨Prod.snd_surjective, continuous_snd, isOpenMap_snd⟩ - -theorem isQuotientMap_fst [Nonempty Y] : IsQuotientMap (Prod.fst : X × Y → X) := - isOpenQuotientMap_fst.isQuotientMap - -theorem isQuotientMap_snd [Nonempty X] : IsQuotientMap (Prod.snd : X × Y → Y) := - isOpenQuotientMap_snd.isQuotientMap - -theorem IsOpenQuotientMap.prodMap {f : X → Y} {g : Z → W} (hf : IsOpenQuotientMap f) - (hg : IsOpenQuotientMap g) : IsOpenQuotientMap (Prod.map f g) := - ⟨.prodMap hf.1 hg.1, .prodMap hf.2 hg.2, .prodMap hf.3 hg.3⟩ - -theorem isOpenMap_prodMap_iff [Nonempty X] [Nonempty Z] {f : X → Y} {g : Z → W} : - IsOpenMap (Prod.map f g) ↔ IsOpenMap f ∧ IsOpenMap g := by - refine ⟨fun h ↦ ⟨?_, ?_⟩, fun ⟨hf, hg⟩ ↦ hf.prodMap hg⟩ - · rw [(isOpenQuotientMap_fst (Y := Z)).isOpenMap_iff] - exact isOpenMap_fst.comp h - · rw [(isOpenQuotientMap_snd (X := X)).isOpenMap_iff] - exact isOpenMap_snd.comp h - -theorem isOpenQuotientMap_prodMap_iff [Nonempty X] [Nonempty Z] {f : X → Y} {g : Z → W} : - IsOpenQuotientMap (Prod.map f g) ↔ IsOpenQuotientMap f ∧ IsOpenQuotientMap g := by - have : Nonempty Y := .map f inferInstance - have : Nonempty W := .map g inferInstance - grind [isOpenQuotientMap_iff, continuous_prodMap_iff, isOpenMap_prodMap_iff, Prod.map_surjective] - -end Prod - -/-- Open quotient maps are preserved by precomposing with a homeomorphism. -/ -lemma Homeomorph.isOpenQuotient_comp_iff (e : X ≃ₜ Y) {f : Y → Z} : - IsOpenQuotientMap (f ∘ e) ↔ IsOpenQuotientMap f := - ⟨fun h ↦ by simpa [comp_assoc] using h.comp e.symm.isOpenQuotientMap, - fun hf ↦ hf.comp e.isOpenQuotientMap⟩ - -/-- Open quotient maps are preserved by postcomposing with a homeomorphism. -/ -lemma Homeomorph.comp_isOpenQuotientMap_iff (e : Y ≃ₜ Z) {f : X → Y} : - IsOpenQuotientMap (e ∘ f) ↔ IsOpenQuotientMap f := - ⟨fun h ↦ by simpa [← comp_assoc] using e.symm.isOpenQuotientMap.comp h, - fun hf ↦ e.isOpenQuotientMap.comp hf⟩ - theorem Topology.IsInducing.isOpenQuotientMap_of_surjective (ind : IsInducing f) (surj : Function.Surjective f) : IsOpenQuotientMap f where surjective := surj From cdaec27d1b78aef2ac63f01fcad0f7d4fab4ae9a Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 17 Jun 2026 15:12:50 +0200 Subject: [PATCH 132/210] move around --- Mathlib/Topology/Constructions/SumProd.lean | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Mathlib/Topology/Constructions/SumProd.lean b/Mathlib/Topology/Constructions/SumProd.lean index c93aab32b48cea..20d3ea52d1ff3f 100644 --- a/Mathlib/Topology/Constructions/SumProd.lean +++ b/Mathlib/Topology/Constructions/SumProd.lean @@ -630,11 +630,6 @@ lemma isEmbedding_prodMkLeft (y : Y) : IsEmbedding (fun x : X ↦ (x, y)) := lemma isEmbedding_prodMkRight (x : X) : IsEmbedding (Prod.mk x : Y → X × Y) := .of_comp (.prodMk_right x) continuous_snd .id -theorem TopologicalSpace.prod_mono {α β : Type*} {σ₁ σ₂ : TopologicalSpace α} - {τ₁ τ₂ : TopologicalSpace β} (hσ : σ₁ ≤ σ₂) (hτ : τ₁ ≤ τ₂) : - @instTopologicalSpaceProd α β σ₁ τ₁ ≤ @instTopologicalSpaceProd α β σ₂ τ₂ := - le_inf (inf_le_left.trans <| induced_mono hσ) (inf_le_right.trans <| induced_mono hτ) - theorem IsOpenQuotientMap.prodMap {f : X → Y} {g : Z → W} (hf : IsOpenQuotientMap f) (hg : IsOpenQuotientMap g) : IsOpenQuotientMap (Prod.map f g) := ⟨.prodMap hf.1 hg.1, .prodMap hf.2 hg.2, .prodMap hf.3 hg.3⟩ @@ -645,6 +640,11 @@ theorem isOpenQuotientMap_prodMap_iff [Nonempty X] [Nonempty Z] {f : X → Y} {g have : Nonempty W := .map g inferInstance grind [isOpenQuotientMap_iff, continuous_prodMap_iff, isOpenMap_prodMap_iff, Prod.map_surjective] +theorem TopologicalSpace.prod_mono {α β : Type*} {σ₁ σ₂ : TopologicalSpace α} + {τ₁ τ₂ : TopologicalSpace β} (hσ : σ₁ ≤ σ₂) (hτ : τ₁ ≤ τ₂) : + @instTopologicalSpaceProd α β σ₁ τ₁ ≤ @instTopologicalSpaceProd α β σ₂ τ₂ := + le_inf (inf_le_left.trans <| induced_mono hσ) (inf_le_right.trans <| induced_mono hτ) + -- Homeomorphisms between the various product: products of two homeomorphisms, -- as well as commutativity and associativity. See below for the analogous results for sums, -- as well as distributivity, etc. From f456bd59b4da5889a1c4ecc618b93e543fc5df5d Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 17 Jun 2026 15:14:21 +0200 Subject: [PATCH 133/210] move around --- Mathlib/Topology/Constructions/SumProd.lean | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Mathlib/Topology/Constructions/SumProd.lean b/Mathlib/Topology/Constructions/SumProd.lean index c93aab32b48cea..20d3ea52d1ff3f 100644 --- a/Mathlib/Topology/Constructions/SumProd.lean +++ b/Mathlib/Topology/Constructions/SumProd.lean @@ -630,11 +630,6 @@ lemma isEmbedding_prodMkLeft (y : Y) : IsEmbedding (fun x : X ↦ (x, y)) := lemma isEmbedding_prodMkRight (x : X) : IsEmbedding (Prod.mk x : Y → X × Y) := .of_comp (.prodMk_right x) continuous_snd .id -theorem TopologicalSpace.prod_mono {α β : Type*} {σ₁ σ₂ : TopologicalSpace α} - {τ₁ τ₂ : TopologicalSpace β} (hσ : σ₁ ≤ σ₂) (hτ : τ₁ ≤ τ₂) : - @instTopologicalSpaceProd α β σ₁ τ₁ ≤ @instTopologicalSpaceProd α β σ₂ τ₂ := - le_inf (inf_le_left.trans <| induced_mono hσ) (inf_le_right.trans <| induced_mono hτ) - theorem IsOpenQuotientMap.prodMap {f : X → Y} {g : Z → W} (hf : IsOpenQuotientMap f) (hg : IsOpenQuotientMap g) : IsOpenQuotientMap (Prod.map f g) := ⟨.prodMap hf.1 hg.1, .prodMap hf.2 hg.2, .prodMap hf.3 hg.3⟩ @@ -645,6 +640,11 @@ theorem isOpenQuotientMap_prodMap_iff [Nonempty X] [Nonempty Z] {f : X → Y} {g have : Nonempty W := .map g inferInstance grind [isOpenQuotientMap_iff, continuous_prodMap_iff, isOpenMap_prodMap_iff, Prod.map_surjective] +theorem TopologicalSpace.prod_mono {α β : Type*} {σ₁ σ₂ : TopologicalSpace α} + {τ₁ τ₂ : TopologicalSpace β} (hσ : σ₁ ≤ σ₂) (hτ : τ₁ ≤ τ₂) : + @instTopologicalSpaceProd α β σ₁ τ₁ ≤ @instTopologicalSpaceProd α β σ₂ τ₂ := + le_inf (inf_le_left.trans <| induced_mono hσ) (inf_le_right.trans <| induced_mono hτ) + -- Homeomorphisms between the various product: products of two homeomorphisms, -- as well as commutativity and associativity. See below for the analogous results for sums, -- as well as distributivity, etc. From f0fc5cab8315372a84cd54038e252a30733cd5b6 Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Tue, 23 Jun 2026 11:48:25 +0200 Subject: [PATCH 134/210] Apply suggestions from code review --- .../Analysis/Normed/Operator/Perturbation/StrictByFinite.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index f2d90890c7d88e..9298a9263c7c13 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -95,7 +95,7 @@ theorem step1 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) S_compl_A.symm.isTopCompl_of_finiteDimensional_quotient A_closed |>.symm replace uS_compl_uA : IsTopCompl (map u.toLinearMap S) (map u.toLinearMap A) := uS_compl_uA.symm.isTopCompl_of_isClosed_of_finiteDimensional uA_closed |>.symm - -- Thus, we have decomposed both the comain and the codomain into topopological complements, + -- Thus, we have decomposed both the domain and the codomain into topopological complements, -- and `u` preserves this decomposition, inducing maps `uₛ : S → map u S` and `uₐ : A → map u A`. set uₛ : S →L[𝕜] map u.toLinearMap S := u.restrict (fun _ ↦ mem_map_of_mem) set uₐ : A →L[𝕜] map u.toLinearMap A := u.restrict (fun _ ↦ mem_map_of_mem) From 6377d9250f205a8f1dd2251ba76b8881e41c88f7 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 23 Jun 2026 12:05:22 +0200 Subject: [PATCH 135/210] Fix build --- Mathlib/Topology/Maps/Strict/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index f2979bf14b8a65..4b8eb5ce7cb537 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -196,7 +196,7 @@ lemma isStrictMap_prodMap (hf : IsStrictMap f) (hg : IsStrictMap g) : IsStrictMap (f.prodMap g) := by rw [isStrictMap_iff_isOpenQuotientMap_rangeRestrict] at hf hg ⊢ let aux : (f.prodMap g).range ≃ₜ f.range × g.range := - (Homeomorph.setCongr (by simp)).trans (Homeomorph.Set.prod _ _) + (Homeomorph.setCongr (by simp [Subgroup.coe_prod])).trans (Homeomorph.Set.prod _ _) exact aux.symm.isOpenQuotientMap.comp (hf.prodMap hg) -- TODO Add the lemma `isStrictMap_piMap` once `MonoidHom.piMap` has been defined. From f2ded477cd7a980caec5d8055b70a10baba95767 Mon Sep 17 00:00:00 2001 From: zw810-ctrl Date: Tue, 23 Jun 2026 19:55:57 -0400 Subject: [PATCH 136/210] Apply suggestion from @ADedecker Co-authored-by: Anatole Dedecker --- Mathlib/Topology/Maps/Strict/Basic.lean | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index 4b8eb5ce7cb537..f0d6196713abee 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -45,7 +45,8 @@ important properties of a strict group homomorphisms `f` : * `isStrictMap_iff_isOpenQuotientMap_rangeRestrict`: `f` is a strict group homomorphism if and only if the `rangeRestrict` of `f` is an open quotient map. -* `isStrictMap_prodMap`: The product (in the sense of Prod.map) of group homomorphisms is strict +* `isStrictMap_prodMap`: The product (in the sense of Prod.map) of strict group homomorphisms +is strict. -/ @[expose] public section From efacaa77fe39f73d419fc03aeccabb235c305c1e Mon Sep 17 00:00:00 2001 From: zw810-ctrl Date: Tue, 23 Jun 2026 19:56:34 -0400 Subject: [PATCH 137/210] Apply suggestion from @ADedecker Co-authored-by: Anatole Dedecker --- Mathlib/Topology/Maps/Strict/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index f0d6196713abee..d75fc8c65c0880 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -167,7 +167,7 @@ lemma isEmbedding_iff_isStrictMap_injective : (Homeomorph.Quotient.congrRight <| by simp [f_inj.eq_iff]).trans Homeomorph.quotientBot exact f_strict.comp Φ.symm.isEmbedding -/-- Strict maps are preserved and reflected when precomposing with a homeomorphism. -/ +/-- Strict maps are preserved when precomposing with a homeomorphism. -/ lemma Homeomorph.isStrictMap_comp_iff (e : X ≃ₜ Y) {f : Y → Z} : IsStrictMap (f ∘ e) ↔ IsStrictMap f := e.isQuotientMap.isStrictMap_iff.symm From 240e2ec476b369ce9f71af05a85c9da13bd69485 Mon Sep 17 00:00:00 2001 From: zw810-ctrl Date: Tue, 23 Jun 2026 19:57:11 -0400 Subject: [PATCH 138/210] Apply suggestions from code review Co-authored-by: Anatole Dedecker --- Mathlib/Topology/Maps/Strict/Basic.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index d75fc8c65c0880..a905f48e11a481 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -185,15 +185,15 @@ variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] (f : G [TopologicalSpace G] [IsTopologicalGroup G] [TopologicalSpace H] /-- A group homomorphism is strict if and only if its rangeRestrict is an open quotient map. -/ -lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict : +@[to_additive] lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict : IsStrictMap f ↔ IsOpenQuotientMap f.rangeRestrict := by rw [isQuotientMap_iff_isOpenQuotientMap] rfl -variable [TopologicalSpace G'] [IsTopologicalGroup G'] [TopologicalSpace H'] +variable {f g} [TopologicalSpace G'] [IsTopologicalGroup G'] [TopologicalSpace H'] -/-- The product (in the sense of `Prod.map`) of group homomorphisms is strict -/ -lemma isStrictMap_prodMap (hf : IsStrictMap f) (hg : IsStrictMap g) : +/-- The product (in the sense of `Prod.map`) of strict group homomorphisms is strict -/ +@[to_additive isStrictMap_prodMap] lemma isStrictMap_prodMap (hf : IsStrictMap f) (hg : IsStrictMap g) : IsStrictMap (f.prodMap g) := by rw [isStrictMap_iff_isOpenQuotientMap_rangeRestrict] at hf hg ⊢ let aux : (f.prodMap g).range ≃ₜ f.range × g.range := From 54e6fc0f02ff53bd64c028d986da9baebf30418f Mon Sep 17 00:00:00 2001 From: zw810-ctrl Date: Tue, 23 Jun 2026 19:57:28 -0400 Subject: [PATCH 139/210] Apply suggestion from @ADedecker Co-authored-by: Anatole Dedecker --- Mathlib/Topology/Maps/Strict/Basic.lean | 402 ++++++++++++------------ 1 file changed, 201 insertions(+), 201 deletions(-) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index a905f48e11a481..6c9d27a39c7403 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -1,205 +1,205 @@ -/- -Copyright (c) 2026 Ziyan Wei. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Ziyan Wei, Anatole Dedecker --/ -module - -public import Mathlib.Topology.Maps.Basic -public import Mathlib.Topology.Homeomorph.Quotient -public import Mathlib.Topology.Constructions -public import Mathlib.Data.Setoid.Basic -public import Mathlib.Topology.Algebra.Group.Quotient - -/-! -# Bourbaki Strict Maps - -This file defines Bourbaki strict maps (`Topology.IsStrictMap`) and proves some of their -basic properties. - -A map `f : X → Y` between topological spaces is called *strict* in the sense of Bourbaki -if the natural corestriction to its image (i.e., `Set.rangeFactorization f`) is a quotient map. -Equivalently, these are precisely the maps for which the first isomorphism -theorem yields a homeomorphism: the canonical bijection `X ⧸ ker f ≃ range f` -is a homeomorphism if and only if `f` is strict. This provides a natural -generalization of quotient maps to non-surjective maps. - -Many important classes of maps are automatically continuous strict maps, including: -- continuous open maps (`IsOpenMap.isStrictMap`); -- continuous closed maps (`IsClosedMap.isStrictMap`). - -## Equivalent characterizations - -We provide several equivalent ways to characterize a strict map `f`: -* `Topology.isStrictMap_iff_isHomeomorph_quotientKerEquivRange`: `f` is strict if and only if - the canonical bijection `Quotient (Setoid.ker f) ≃ Set.range f` is a homeomorphism. -* `Topology.isStrictMap_iff_isEmbedding_kerLift`: `f` is strict if and only if - the canonical injection `Quotient (Setoid.ker f) → Y` (`Setoid.kerLift f`) is an embedding. - -### Group homomorphisms - -In general, the product (in the sense of `Prod.map`) of two strict maps need not be strict. -But thanks to `MonoidHom.isOpenQuotientMap_of_isQuotientMap`, we can replace `IsQuotientMap` -by `IsOpenQuotientMap` in the setting of group homomorphisms. Therefore we provide several -important properties of a strict group homomorphisms `f` : - -* `isStrictMap_iff_isOpenQuotientMap_rangeRestrict`: `f` is a strict group homomorphism if - and only if the `rangeRestrict` of `f` is an open quotient map. -* `isStrictMap_prodMap`: The product (in the sense of Prod.map) of strict group homomorphisms -is strict. --/ - -@[expose] public section - -open Function Set Topology Setoid - -namespace Topology - -variable {X Y Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] - (f : X → Y) {g : Y → Z} - -/-- A map is a strict map in the sense of Bourbaki if the natural map to its image -is a quotient map. -/ -def IsStrictMap : Prop := - IsQuotientMap (Set.rangeFactorization f) - -lemma isStrictMap_iff_isQuotientMap_rangeFactorization : - IsStrictMap f ↔ IsQuotientMap (Set.rangeFactorization f) := - Iff.rfl - -variable {f} - -/-- A map is a strict map if and only if the canonical bijection -`Quotient (Setoid.ker f) ≃ Set.range f` is a homeomorphism. -/ -theorem isStrictMap_iff_isHomeomorph_quotientKerEquivRange : - IsStrictMap f ↔ - IsHomeomorph (Setoid.quotientKerEquivRange f : Quotient (Setoid.ker f) → Set.range f) := by - simp only [IsStrictMap, isHomeomorph_iff_isQuotientMap_injective, Equiv.injective, and_true] - exact ⟨fun h => IsQuotientMap.of_comp_isQuotientMap isQuotientMap_quotient_mk' h, - fun h ↦ h.comp isQuotientMap_quotient_mk'⟩ - -/-- The homeomorphism `Quotient (Setoid.ker f) ≃ₜ Set.range f` given by a strict map `f`. -This is the homeomorphism obtained from the first isomorphism theorem. -/ -noncomputable def Homeomorph.quotientKerEquivRange (hf : IsStrictMap f) : - Quotient (Setoid.ker f) ≃ₜ Set.range f := - (isStrictMap_iff_isHomeomorph_quotientKerEquivRange.mp hf).homeomorph - -/-- A map is a strict map if and only if the canonical injection `Quotient (Setoid.ker f) → Y` -(`Setoid.kerLift f`) is an embedding. -/ -theorem isStrictMap_iff_isEmbedding_kerLift : - IsStrictMap f ↔ IsEmbedding (Setoid.kerLift f) := by - simp only [isStrictMap_iff_isHomeomorph_quotientKerEquivRange, - isHomeomorph_iff_isEmbedding_surjective, Equiv.surjective, and_true] - exact (IsEmbedding.of_comp_iff .subtypeVal).symm - -/-- A strict map is continuous, since the range factorization is continuous. -/ -lemma IsStrictMap.continuous {f : X → Y} (hf : IsStrictMap f) : Continuous f := by - rw [isStrictMap_iff_isQuotientMap_rangeFactorization] at hf - exact continuous_rangeFactorization_iff.mp hf.continuous - -/-- A open continuous map is a strict map. -/ -lemma IsOpenMap.isStrictMap (ho : IsOpenMap f) (h_cont : Continuous f) : - IsStrictMap f := by - rw [isStrictMap_iff_isQuotientMap_rangeFactorization] - exact (ho.subtype_mk fun x => ⟨x, rfl⟩).isQuotientMap - h_cont.rangeFactorization Set.rangeFactorization_surjective - -/-- A closed continuous map is a strict map. -/ -lemma IsClosedMap.isStrictMap (hc : IsClosedMap f) (h_cont : Continuous f) : - IsStrictMap f := by - rw [isStrictMap_iff_isQuotientMap_rangeFactorization] - exact (hc.subtype_mk fun x => ⟨x, rfl⟩).isQuotientMap - h_cont.rangeFactorization Set.rangeFactorization_surjective - -/-- A homeomorphism is a strict map. -/ -lemma IsHomeomorph.isStrictMap (f_homeo : IsHomeomorph f) : - IsStrictMap f := - f_homeo.isOpenMap.isStrictMap f_homeo.continuous - -/-- The identity is a strict map. -/ -lemma IsStrictMap.id : IsStrictMap (id : X → X) := IsHomeomorph.id.isStrictMap - -/-- Assume that `f : X → Y` is a quotient map. Then `g : Y → Z` is strict -if and only if `g ∘ f` is strict. -/ -lemma IsQuotientMap.isStrictMap_iff (f_quot : IsQuotientMap f) : - IsStrictMap g ↔ IsStrictMap (g ∘ f) := by - set Φ : range (g ∘ f) ≃ₜ range g := .setCongr <| f_quot.surjective.range_comp g - have key : rangeFactorization g ∘ f = Φ ∘ rangeFactorization (g ∘ f) := rfl - simp_rw [isStrictMap_iff_isQuotientMap_rangeFactorization, ← f_quot.of_comp_iff, key] - exact ⟨fun H ↦ by simpa using! Φ.symm.isQuotientMap.comp H, fun H ↦ Φ.isQuotientMap.comp H⟩ - -/-- A quotient map is strict. See also `isQuotientMap_iff_isStrictMap_surjective`. -/ -lemma IsQuotientMap.isStrictMap (f_quot : IsQuotientMap f) : - IsStrictMap f := - f_quot.isStrictMap_iff.mp .id - -/-- Assume that `g : Y → Z` is an embedding. Then `f : X → Y` is strict -if and only if `g ∘ f` is strict. -/ -lemma IsEmbedding.isStrictMap_iff (g_emb : IsEmbedding g) : - IsStrictMap f ↔ IsStrictMap (g ∘ f) := by - set Φ : Quotient (Setoid.ker (g ∘ f)) ≃ₜ Quotient (Setoid.ker (f)) := - Homeomorph.Quotient.congrRight (fun _ _ ↦ by simp [g_emb.injective.eq_iff]) - have key : g ∘ kerLift f ∘ Φ = kerLift (g ∘ f) := - funext <| Quotient.ind fun _ ↦ rfl - simp_rw [isStrictMap_iff_isEmbedding_kerLift, ← g_emb.of_comp_iff, ← key] - exact ⟨fun H ↦ H.comp Φ.isEmbedding, - fun H ↦ by simpa [comp_assoc] using H.comp Φ.symm.isEmbedding⟩ - -/-- An embedding is strict. See also `isEmbedding_iff_isStrictMap_injective`. -/ -lemma IsEmbedding.isStrictMap (f_emb : IsEmbedding f) : - IsStrictMap f := - f_emb.isStrictMap_iff.mp .id - -/-- Quotient maps are precisely surjective strict maps. -/ -lemma isQuotientMap_iff_isStrictMap_surjective : - IsQuotientMap f ↔ IsStrictMap f ∧ Surjective f := by - refine ⟨fun H ↦ ⟨H.isStrictMap, H.surjective⟩, fun ⟨f_strict, f_surj⟩ ↦ ?_⟩ - rw [isStrictMap_iff_isQuotientMap_rangeFactorization] at f_strict - set Φ : range f ≃ₜ Y := .trans (.setCongr f_surj.range_eq) (Homeomorph.Set.univ Y) - exact Φ.isQuotientMap.comp f_strict - -/-- Embeddings are precisely injective strict maps. -/ -lemma isEmbedding_iff_isStrictMap_injective : - IsEmbedding f ↔ IsStrictMap f ∧ Injective f := by - refine ⟨fun H ↦ ⟨H.isStrictMap, H.injective⟩, fun ⟨f_strict, f_inj⟩ ↦ ?_⟩ - rw [isStrictMap_iff_isEmbedding_kerLift] at f_strict - set Φ : Quotient (ker f) ≃ₜ X := - (Homeomorph.Quotient.congrRight <| by simp [f_inj.eq_iff]).trans Homeomorph.quotientBot - exact f_strict.comp Φ.symm.isEmbedding - -/-- Strict maps are preserved when precomposing with a homeomorphism. -/ -lemma Homeomorph.isStrictMap_comp_iff (e : X ≃ₜ Y) {f : Y → Z} : - IsStrictMap (f ∘ e) ↔ IsStrictMap f := - e.isQuotientMap.isStrictMap_iff.symm - -/-- Strict maps are preserved and reflected when postcomposing with a homeomorphism. -/ -lemma Homeomorph.comp_isStrictMap_iff (e : Y ≃ₜ Z) {f : X → Y} : - IsStrictMap (e ∘ f) ↔ IsStrictMap f := - e.isEmbedding.isStrictMap_iff.symm - -end Topology - -namespace MonoidHom - -variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] (f : G →* H) (g : G' →* H') - [TopologicalSpace G] [IsTopologicalGroup G] [TopologicalSpace H] - -/-- A group homomorphism is strict if and only if its rangeRestrict is an open quotient map. -/ +/- +Copyright (c) 2026 Ziyan Wei. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Ziyan Wei, Anatole Dedecker +-/ +module + +public import Mathlib.Topology.Maps.Basic +public import Mathlib.Topology.Homeomorph.Quotient +public import Mathlib.Topology.Constructions +public import Mathlib.Data.Setoid.Basic +public import Mathlib.Topology.Algebra.Group.Quotient + +/-! +# Bourbaki Strict Maps + +This file defines Bourbaki strict maps (`Topology.IsStrictMap`) and proves some of their +basic properties. + +A map `f : X → Y` between topological spaces is called *strict* in the sense of Bourbaki +if the natural corestriction to its image (i.e., `Set.rangeFactorization f`) is a quotient map. +Equivalently, these are precisely the maps for which the first isomorphism +theorem yields a homeomorphism: the canonical bijection `X ⧸ ker f ≃ range f` +is a homeomorphism if and only if `f` is strict. This provides a natural +generalization of quotient maps to non-surjective maps. + +Many important classes of maps are automatically continuous strict maps, including: +- continuous open maps (`IsOpenMap.isStrictMap`); +- continuous closed maps (`IsClosedMap.isStrictMap`). + +## Equivalent characterizations + +We provide several equivalent ways to characterize a strict map `f`: +* `Topology.isStrictMap_iff_isHomeomorph_quotientKerEquivRange`: `f` is strict if and only if + the canonical bijection `Quotient (Setoid.ker f) ≃ Set.range f` is a homeomorphism. +* `Topology.isStrictMap_iff_isEmbedding_kerLift`: `f` is strict if and only if + the canonical injection `Quotient (Setoid.ker f) → Y` (`Setoid.kerLift f`) is an embedding. + +### Group homomorphisms + +In general, the product (in the sense of `Prod.map`) of two strict maps need not be strict. +But thanks to `MonoidHom.isOpenQuotientMap_of_isQuotientMap`, we can replace `IsQuotientMap` +by `IsOpenQuotientMap` in the setting of group homomorphisms. Therefore we provide several +important properties of a strict group homomorphisms `f` : + +* `isStrictMap_iff_isOpenQuotientMap_rangeRestrict`: `f` is a strict group homomorphism if + and only if the `rangeRestrict` of `f` is an open quotient map. +* `isStrictMap_prodMap`: The product (in the sense of Prod.map) of strict group homomorphisms +is strict. +-/ + +@[expose] public section + +open Function Set Topology Setoid + +namespace Topology + +variable {X Y Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] + (f : X → Y) {g : Y → Z} + +/-- A map is a strict map in the sense of Bourbaki if the natural map to its image +is a quotient map. -/ +def IsStrictMap : Prop := + IsQuotientMap (Set.rangeFactorization f) + +lemma isStrictMap_iff_isQuotientMap_rangeFactorization : + IsStrictMap f ↔ IsQuotientMap (Set.rangeFactorization f) := + Iff.rfl + +variable {f} + +/-- A map is a strict map if and only if the canonical bijection +`Quotient (Setoid.ker f) ≃ Set.range f` is a homeomorphism. -/ +theorem isStrictMap_iff_isHomeomorph_quotientKerEquivRange : + IsStrictMap f ↔ + IsHomeomorph (Setoid.quotientKerEquivRange f : Quotient (Setoid.ker f) → Set.range f) := by + simp only [IsStrictMap, isHomeomorph_iff_isQuotientMap_injective, Equiv.injective, and_true] + exact ⟨fun h => IsQuotientMap.of_comp_isQuotientMap isQuotientMap_quotient_mk' h, + fun h ↦ h.comp isQuotientMap_quotient_mk'⟩ + +/-- The homeomorphism `Quotient (Setoid.ker f) ≃ₜ Set.range f` given by a strict map `f`. +This is the homeomorphism obtained from the first isomorphism theorem. -/ +noncomputable def Homeomorph.quotientKerEquivRange (hf : IsStrictMap f) : + Quotient (Setoid.ker f) ≃ₜ Set.range f := + (isStrictMap_iff_isHomeomorph_quotientKerEquivRange.mp hf).homeomorph + +/-- A map is a strict map if and only if the canonical injection `Quotient (Setoid.ker f) → Y` +(`Setoid.kerLift f`) is an embedding. -/ +theorem isStrictMap_iff_isEmbedding_kerLift : + IsStrictMap f ↔ IsEmbedding (Setoid.kerLift f) := by + simp only [isStrictMap_iff_isHomeomorph_quotientKerEquivRange, + isHomeomorph_iff_isEmbedding_surjective, Equiv.surjective, and_true] + exact (IsEmbedding.of_comp_iff .subtypeVal).symm + +/-- A strict map is continuous, since the range factorization is continuous. -/ +lemma IsStrictMap.continuous {f : X → Y} (hf : IsStrictMap f) : Continuous f := by + rw [isStrictMap_iff_isQuotientMap_rangeFactorization] at hf + exact continuous_rangeFactorization_iff.mp hf.continuous + +/-- A open continuous map is a strict map. -/ +lemma IsOpenMap.isStrictMap (ho : IsOpenMap f) (h_cont : Continuous f) : + IsStrictMap f := by + rw [isStrictMap_iff_isQuotientMap_rangeFactorization] + exact (ho.subtype_mk fun x => ⟨x, rfl⟩).isQuotientMap + h_cont.rangeFactorization Set.rangeFactorization_surjective + +/-- A closed continuous map is a strict map. -/ +lemma IsClosedMap.isStrictMap (hc : IsClosedMap f) (h_cont : Continuous f) : + IsStrictMap f := by + rw [isStrictMap_iff_isQuotientMap_rangeFactorization] + exact (hc.subtype_mk fun x => ⟨x, rfl⟩).isQuotientMap + h_cont.rangeFactorization Set.rangeFactorization_surjective + +/-- A homeomorphism is a strict map. -/ +lemma IsHomeomorph.isStrictMap (f_homeo : IsHomeomorph f) : + IsStrictMap f := + f_homeo.isOpenMap.isStrictMap f_homeo.continuous + +/-- The identity is a strict map. -/ +lemma IsStrictMap.id : IsStrictMap (id : X → X) := IsHomeomorph.id.isStrictMap + +/-- Assume that `f : X → Y` is a quotient map. Then `g : Y → Z` is strict +if and only if `g ∘ f` is strict. -/ +lemma IsQuotientMap.isStrictMap_iff (f_quot : IsQuotientMap f) : + IsStrictMap g ↔ IsStrictMap (g ∘ f) := by + set Φ : range (g ∘ f) ≃ₜ range g := .setCongr <| f_quot.surjective.range_comp g + have key : rangeFactorization g ∘ f = Φ ∘ rangeFactorization (g ∘ f) := rfl + simp_rw [isStrictMap_iff_isQuotientMap_rangeFactorization, ← f_quot.of_comp_iff, key] + exact ⟨fun H ↦ by simpa using! Φ.symm.isQuotientMap.comp H, fun H ↦ Φ.isQuotientMap.comp H⟩ + +/-- A quotient map is strict. See also `isQuotientMap_iff_isStrictMap_surjective`. -/ +lemma IsQuotientMap.isStrictMap (f_quot : IsQuotientMap f) : + IsStrictMap f := + f_quot.isStrictMap_iff.mp .id + +/-- Assume that `g : Y → Z` is an embedding. Then `f : X → Y` is strict +if and only if `g ∘ f` is strict. -/ +lemma IsEmbedding.isStrictMap_iff (g_emb : IsEmbedding g) : + IsStrictMap f ↔ IsStrictMap (g ∘ f) := by + set Φ : Quotient (Setoid.ker (g ∘ f)) ≃ₜ Quotient (Setoid.ker (f)) := + Homeomorph.Quotient.congrRight (fun _ _ ↦ by simp [g_emb.injective.eq_iff]) + have key : g ∘ kerLift f ∘ Φ = kerLift (g ∘ f) := + funext <| Quotient.ind fun _ ↦ rfl + simp_rw [isStrictMap_iff_isEmbedding_kerLift, ← g_emb.of_comp_iff, ← key] + exact ⟨fun H ↦ H.comp Φ.isEmbedding, + fun H ↦ by simpa [comp_assoc] using H.comp Φ.symm.isEmbedding⟩ + +/-- An embedding is strict. See also `isEmbedding_iff_isStrictMap_injective`. -/ +lemma IsEmbedding.isStrictMap (f_emb : IsEmbedding f) : + IsStrictMap f := + f_emb.isStrictMap_iff.mp .id + +/-- Quotient maps are precisely surjective strict maps. -/ +lemma isQuotientMap_iff_isStrictMap_surjective : + IsQuotientMap f ↔ IsStrictMap f ∧ Surjective f := by + refine ⟨fun H ↦ ⟨H.isStrictMap, H.surjective⟩, fun ⟨f_strict, f_surj⟩ ↦ ?_⟩ + rw [isStrictMap_iff_isQuotientMap_rangeFactorization] at f_strict + set Φ : range f ≃ₜ Y := .trans (.setCongr f_surj.range_eq) (Homeomorph.Set.univ Y) + exact Φ.isQuotientMap.comp f_strict + +/-- Embeddings are precisely injective strict maps. -/ +lemma isEmbedding_iff_isStrictMap_injective : + IsEmbedding f ↔ IsStrictMap f ∧ Injective f := by + refine ⟨fun H ↦ ⟨H.isStrictMap, H.injective⟩, fun ⟨f_strict, f_inj⟩ ↦ ?_⟩ + rw [isStrictMap_iff_isEmbedding_kerLift] at f_strict + set Φ : Quotient (ker f) ≃ₜ X := + (Homeomorph.Quotient.congrRight <| by simp [f_inj.eq_iff]).trans Homeomorph.quotientBot + exact f_strict.comp Φ.symm.isEmbedding + +/-- Strict maps are preserved when precomposing with a homeomorphism. -/ +lemma Homeomorph.isStrictMap_comp_iff (e : X ≃ₜ Y) {f : Y → Z} : + IsStrictMap (f ∘ e) ↔ IsStrictMap f := + e.isQuotientMap.isStrictMap_iff.symm + +/-- Strict maps are preserved when postcomposing with a homeomorphism. -/ +lemma Homeomorph.comp_isStrictMap_iff (e : Y ≃ₜ Z) {f : X → Y} : + IsStrictMap (e ∘ f) ↔ IsStrictMap f := + e.isEmbedding.isStrictMap_iff.symm + +end Topology + +namespace MonoidHom + +variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] (f : G →* H) (g : G' →* H') + [TopologicalSpace G] [IsTopologicalGroup G] [TopologicalSpace H] + +/-- A group homomorphism is strict if and only if its rangeRestrict is an open quotient map. -/ @[to_additive] lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict : - IsStrictMap f ↔ IsOpenQuotientMap f.rangeRestrict := by - rw [isQuotientMap_iff_isOpenQuotientMap] - rfl - + IsStrictMap f ↔ IsOpenQuotientMap f.rangeRestrict := by + rw [isQuotientMap_iff_isOpenQuotientMap] + rfl + variable {f g} [TopologicalSpace G'] [IsTopologicalGroup G'] [TopologicalSpace H'] - + /-- The product (in the sense of `Prod.map`) of strict group homomorphisms is strict -/ @[to_additive isStrictMap_prodMap] lemma isStrictMap_prodMap (hf : IsStrictMap f) (hg : IsStrictMap g) : - IsStrictMap (f.prodMap g) := by - rw [isStrictMap_iff_isOpenQuotientMap_rangeRestrict] at hf hg ⊢ - let aux : (f.prodMap g).range ≃ₜ f.range × g.range := - (Homeomorph.setCongr (by simp [Subgroup.coe_prod])).trans (Homeomorph.Set.prod _ _) - exact aux.symm.isOpenQuotientMap.comp (hf.prodMap hg) - --- TODO Add the lemma `isStrictMap_piMap` once `MonoidHom.piMap` has been defined. - -end MonoidHom + IsStrictMap (f.prodMap g) := by + rw [isStrictMap_iff_isOpenQuotientMap_rangeRestrict] at hf hg ⊢ + let aux : (f.prodMap g).range ≃ₜ f.range × g.range := + (Homeomorph.setCongr (by simp [Subgroup.coe_prod])).trans (Homeomorph.Set.prod _ _) + exact aux.symm.isOpenQuotientMap.comp (hf.prodMap hg) + +-- TODO Add the lemma `isStrictMap_piMap` once `MonoidHom.piMap` has been defined. + +end MonoidHom From 15b82befad3977212db3b981c47df7096af4bc00 Mon Sep 17 00:00:00 2001 From: zw810-ctrl Date: Tue, 23 Jun 2026 19:57:52 -0400 Subject: [PATCH 140/210] Apply suggestion from @plp127 Co-authored-by: Aaron Liu --- Mathlib/Topology/Algebra/Group/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Topology/Algebra/Group/Basic.lean b/Mathlib/Topology/Algebra/Group/Basic.lean index 5a8a38b6cb211d..39c50524f14460 100644 --- a/Mathlib/Topology/Algebra/Group/Basic.lean +++ b/Mathlib/Topology/Algebra/Group/Basic.lean @@ -915,7 +915,7 @@ lemma MonoidHom.isOpenQuotientMap_of_isQuotientMap {A : Type*} [Group A] rw [map_mul, hk, mul_one] @[to_additive] -lemma MonoidHom.isQuotientMap_iff_isOpenQuotientMap {A : Type*} [Group A] +lemma MonoidHom.isOpenQuotientMap_iff_isQuotientMap {A : Type*} [Group A] [TopologicalSpace A] [ContinuousMul A] {B : Type*} [Group B] [TopologicalSpace B] {F : Type*} [FunLike F A B] [MonoidHomClass F A B] {φ : F} : IsOpenQuotientMap φ ↔ IsQuotientMap φ := From 7cb397e38d71368292099cd59ee04b6a5849860a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Tue, 23 Jun 2026 23:58:30 +0000 Subject: [PATCH 141/210] [pre-commit.ci lite] apply automatic fixes --- Mathlib/Topology/Maps/Strict/Basic.lean | 410 ++++++++++++------------ 1 file changed, 205 insertions(+), 205 deletions(-) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index 6c9d27a39c7403..d646e5eaaf1b93 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -1,205 +1,205 @@ -/- -Copyright (c) 2026 Ziyan Wei. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Ziyan Wei, Anatole Dedecker --/ -module - -public import Mathlib.Topology.Maps.Basic -public import Mathlib.Topology.Homeomorph.Quotient -public import Mathlib.Topology.Constructions -public import Mathlib.Data.Setoid.Basic -public import Mathlib.Topology.Algebra.Group.Quotient - -/-! -# Bourbaki Strict Maps - -This file defines Bourbaki strict maps (`Topology.IsStrictMap`) and proves some of their -basic properties. - -A map `f : X → Y` between topological spaces is called *strict* in the sense of Bourbaki -if the natural corestriction to its image (i.e., `Set.rangeFactorization f`) is a quotient map. -Equivalently, these are precisely the maps for which the first isomorphism -theorem yields a homeomorphism: the canonical bijection `X ⧸ ker f ≃ range f` -is a homeomorphism if and only if `f` is strict. This provides a natural -generalization of quotient maps to non-surjective maps. - -Many important classes of maps are automatically continuous strict maps, including: -- continuous open maps (`IsOpenMap.isStrictMap`); -- continuous closed maps (`IsClosedMap.isStrictMap`). - -## Equivalent characterizations - -We provide several equivalent ways to characterize a strict map `f`: -* `Topology.isStrictMap_iff_isHomeomorph_quotientKerEquivRange`: `f` is strict if and only if - the canonical bijection `Quotient (Setoid.ker f) ≃ Set.range f` is a homeomorphism. -* `Topology.isStrictMap_iff_isEmbedding_kerLift`: `f` is strict if and only if - the canonical injection `Quotient (Setoid.ker f) → Y` (`Setoid.kerLift f`) is an embedding. - -### Group homomorphisms - -In general, the product (in the sense of `Prod.map`) of two strict maps need not be strict. -But thanks to `MonoidHom.isOpenQuotientMap_of_isQuotientMap`, we can replace `IsQuotientMap` -by `IsOpenQuotientMap` in the setting of group homomorphisms. Therefore we provide several -important properties of a strict group homomorphisms `f` : - -* `isStrictMap_iff_isOpenQuotientMap_rangeRestrict`: `f` is a strict group homomorphism if - and only if the `rangeRestrict` of `f` is an open quotient map. -* `isStrictMap_prodMap`: The product (in the sense of Prod.map) of strict group homomorphisms -is strict. --/ - -@[expose] public section - -open Function Set Topology Setoid - -namespace Topology - -variable {X Y Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] - (f : X → Y) {g : Y → Z} - -/-- A map is a strict map in the sense of Bourbaki if the natural map to its image -is a quotient map. -/ -def IsStrictMap : Prop := - IsQuotientMap (Set.rangeFactorization f) - -lemma isStrictMap_iff_isQuotientMap_rangeFactorization : - IsStrictMap f ↔ IsQuotientMap (Set.rangeFactorization f) := - Iff.rfl - -variable {f} - -/-- A map is a strict map if and only if the canonical bijection -`Quotient (Setoid.ker f) ≃ Set.range f` is a homeomorphism. -/ -theorem isStrictMap_iff_isHomeomorph_quotientKerEquivRange : - IsStrictMap f ↔ - IsHomeomorph (Setoid.quotientKerEquivRange f : Quotient (Setoid.ker f) → Set.range f) := by - simp only [IsStrictMap, isHomeomorph_iff_isQuotientMap_injective, Equiv.injective, and_true] - exact ⟨fun h => IsQuotientMap.of_comp_isQuotientMap isQuotientMap_quotient_mk' h, - fun h ↦ h.comp isQuotientMap_quotient_mk'⟩ - -/-- The homeomorphism `Quotient (Setoid.ker f) ≃ₜ Set.range f` given by a strict map `f`. -This is the homeomorphism obtained from the first isomorphism theorem. -/ -noncomputable def Homeomorph.quotientKerEquivRange (hf : IsStrictMap f) : - Quotient (Setoid.ker f) ≃ₜ Set.range f := - (isStrictMap_iff_isHomeomorph_quotientKerEquivRange.mp hf).homeomorph - -/-- A map is a strict map if and only if the canonical injection `Quotient (Setoid.ker f) → Y` -(`Setoid.kerLift f`) is an embedding. -/ -theorem isStrictMap_iff_isEmbedding_kerLift : - IsStrictMap f ↔ IsEmbedding (Setoid.kerLift f) := by - simp only [isStrictMap_iff_isHomeomorph_quotientKerEquivRange, - isHomeomorph_iff_isEmbedding_surjective, Equiv.surjective, and_true] - exact (IsEmbedding.of_comp_iff .subtypeVal).symm - -/-- A strict map is continuous, since the range factorization is continuous. -/ -lemma IsStrictMap.continuous {f : X → Y} (hf : IsStrictMap f) : Continuous f := by - rw [isStrictMap_iff_isQuotientMap_rangeFactorization] at hf - exact continuous_rangeFactorization_iff.mp hf.continuous - -/-- A open continuous map is a strict map. -/ -lemma IsOpenMap.isStrictMap (ho : IsOpenMap f) (h_cont : Continuous f) : - IsStrictMap f := by - rw [isStrictMap_iff_isQuotientMap_rangeFactorization] - exact (ho.subtype_mk fun x => ⟨x, rfl⟩).isQuotientMap - h_cont.rangeFactorization Set.rangeFactorization_surjective - -/-- A closed continuous map is a strict map. -/ -lemma IsClosedMap.isStrictMap (hc : IsClosedMap f) (h_cont : Continuous f) : - IsStrictMap f := by - rw [isStrictMap_iff_isQuotientMap_rangeFactorization] - exact (hc.subtype_mk fun x => ⟨x, rfl⟩).isQuotientMap - h_cont.rangeFactorization Set.rangeFactorization_surjective - -/-- A homeomorphism is a strict map. -/ -lemma IsHomeomorph.isStrictMap (f_homeo : IsHomeomorph f) : - IsStrictMap f := - f_homeo.isOpenMap.isStrictMap f_homeo.continuous - -/-- The identity is a strict map. -/ -lemma IsStrictMap.id : IsStrictMap (id : X → X) := IsHomeomorph.id.isStrictMap - -/-- Assume that `f : X → Y` is a quotient map. Then `g : Y → Z` is strict -if and only if `g ∘ f` is strict. -/ -lemma IsQuotientMap.isStrictMap_iff (f_quot : IsQuotientMap f) : - IsStrictMap g ↔ IsStrictMap (g ∘ f) := by - set Φ : range (g ∘ f) ≃ₜ range g := .setCongr <| f_quot.surjective.range_comp g - have key : rangeFactorization g ∘ f = Φ ∘ rangeFactorization (g ∘ f) := rfl - simp_rw [isStrictMap_iff_isQuotientMap_rangeFactorization, ← f_quot.of_comp_iff, key] - exact ⟨fun H ↦ by simpa using! Φ.symm.isQuotientMap.comp H, fun H ↦ Φ.isQuotientMap.comp H⟩ - -/-- A quotient map is strict. See also `isQuotientMap_iff_isStrictMap_surjective`. -/ -lemma IsQuotientMap.isStrictMap (f_quot : IsQuotientMap f) : - IsStrictMap f := - f_quot.isStrictMap_iff.mp .id - -/-- Assume that `g : Y → Z` is an embedding. Then `f : X → Y` is strict -if and only if `g ∘ f` is strict. -/ -lemma IsEmbedding.isStrictMap_iff (g_emb : IsEmbedding g) : - IsStrictMap f ↔ IsStrictMap (g ∘ f) := by - set Φ : Quotient (Setoid.ker (g ∘ f)) ≃ₜ Quotient (Setoid.ker (f)) := - Homeomorph.Quotient.congrRight (fun _ _ ↦ by simp [g_emb.injective.eq_iff]) - have key : g ∘ kerLift f ∘ Φ = kerLift (g ∘ f) := - funext <| Quotient.ind fun _ ↦ rfl - simp_rw [isStrictMap_iff_isEmbedding_kerLift, ← g_emb.of_comp_iff, ← key] - exact ⟨fun H ↦ H.comp Φ.isEmbedding, - fun H ↦ by simpa [comp_assoc] using H.comp Φ.symm.isEmbedding⟩ - -/-- An embedding is strict. See also `isEmbedding_iff_isStrictMap_injective`. -/ -lemma IsEmbedding.isStrictMap (f_emb : IsEmbedding f) : - IsStrictMap f := - f_emb.isStrictMap_iff.mp .id - -/-- Quotient maps are precisely surjective strict maps. -/ -lemma isQuotientMap_iff_isStrictMap_surjective : - IsQuotientMap f ↔ IsStrictMap f ∧ Surjective f := by - refine ⟨fun H ↦ ⟨H.isStrictMap, H.surjective⟩, fun ⟨f_strict, f_surj⟩ ↦ ?_⟩ - rw [isStrictMap_iff_isQuotientMap_rangeFactorization] at f_strict - set Φ : range f ≃ₜ Y := .trans (.setCongr f_surj.range_eq) (Homeomorph.Set.univ Y) - exact Φ.isQuotientMap.comp f_strict - -/-- Embeddings are precisely injective strict maps. -/ -lemma isEmbedding_iff_isStrictMap_injective : - IsEmbedding f ↔ IsStrictMap f ∧ Injective f := by - refine ⟨fun H ↦ ⟨H.isStrictMap, H.injective⟩, fun ⟨f_strict, f_inj⟩ ↦ ?_⟩ - rw [isStrictMap_iff_isEmbedding_kerLift] at f_strict - set Φ : Quotient (ker f) ≃ₜ X := - (Homeomorph.Quotient.congrRight <| by simp [f_inj.eq_iff]).trans Homeomorph.quotientBot - exact f_strict.comp Φ.symm.isEmbedding - -/-- Strict maps are preserved when precomposing with a homeomorphism. -/ -lemma Homeomorph.isStrictMap_comp_iff (e : X ≃ₜ Y) {f : Y → Z} : - IsStrictMap (f ∘ e) ↔ IsStrictMap f := - e.isQuotientMap.isStrictMap_iff.symm - -/-- Strict maps are preserved when postcomposing with a homeomorphism. -/ -lemma Homeomorph.comp_isStrictMap_iff (e : Y ≃ₜ Z) {f : X → Y} : - IsStrictMap (e ∘ f) ↔ IsStrictMap f := - e.isEmbedding.isStrictMap_iff.symm - -end Topology - -namespace MonoidHom - -variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] (f : G →* H) (g : G' →* H') - [TopologicalSpace G] [IsTopologicalGroup G] [TopologicalSpace H] - -/-- A group homomorphism is strict if and only if its rangeRestrict is an open quotient map. -/ -@[to_additive] lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict : - IsStrictMap f ↔ IsOpenQuotientMap f.rangeRestrict := by - rw [isQuotientMap_iff_isOpenQuotientMap] - rfl - -variable {f g} [TopologicalSpace G'] [IsTopologicalGroup G'] [TopologicalSpace H'] - -/-- The product (in the sense of `Prod.map`) of strict group homomorphisms is strict -/ -@[to_additive isStrictMap_prodMap] lemma isStrictMap_prodMap (hf : IsStrictMap f) (hg : IsStrictMap g) : - IsStrictMap (f.prodMap g) := by - rw [isStrictMap_iff_isOpenQuotientMap_rangeRestrict] at hf hg ⊢ - let aux : (f.prodMap g).range ≃ₜ f.range × g.range := - (Homeomorph.setCongr (by simp [Subgroup.coe_prod])).trans (Homeomorph.Set.prod _ _) - exact aux.symm.isOpenQuotientMap.comp (hf.prodMap hg) - --- TODO Add the lemma `isStrictMap_piMap` once `MonoidHom.piMap` has been defined. - -end MonoidHom +/- +Copyright (c) 2026 Ziyan Wei. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Ziyan Wei, Anatole Dedecker +-/ +module + +public import Mathlib.Topology.Maps.Basic +public import Mathlib.Topology.Homeomorph.Quotient +public import Mathlib.Topology.Constructions +public import Mathlib.Data.Setoid.Basic +public import Mathlib.Topology.Algebra.Group.Quotient + +/-! +# Bourbaki Strict Maps + +This file defines Bourbaki strict maps (`Topology.IsStrictMap`) and proves some of their +basic properties. + +A map `f : X → Y` between topological spaces is called *strict* in the sense of Bourbaki +if the natural corestriction to its image (i.e., `Set.rangeFactorization f`) is a quotient map. +Equivalently, these are precisely the maps for which the first isomorphism +theorem yields a homeomorphism: the canonical bijection `X ⧸ ker f ≃ range f` +is a homeomorphism if and only if `f` is strict. This provides a natural +generalization of quotient maps to non-surjective maps. + +Many important classes of maps are automatically continuous strict maps, including: +- continuous open maps (`IsOpenMap.isStrictMap`); +- continuous closed maps (`IsClosedMap.isStrictMap`). + +## Equivalent characterizations + +We provide several equivalent ways to characterize a strict map `f`: +* `Topology.isStrictMap_iff_isHomeomorph_quotientKerEquivRange`: `f` is strict if and only if + the canonical bijection `Quotient (Setoid.ker f) ≃ Set.range f` is a homeomorphism. +* `Topology.isStrictMap_iff_isEmbedding_kerLift`: `f` is strict if and only if + the canonical injection `Quotient (Setoid.ker f) → Y` (`Setoid.kerLift f`) is an embedding. + +### Group homomorphisms + +In general, the product (in the sense of `Prod.map`) of two strict maps need not be strict. +But thanks to `MonoidHom.isOpenQuotientMap_of_isQuotientMap`, we can replace `IsQuotientMap` +by `IsOpenQuotientMap` in the setting of group homomorphisms. Therefore we provide several +important properties of a strict group homomorphisms `f` : + +* `isStrictMap_iff_isOpenQuotientMap_rangeRestrict`: `f` is a strict group homomorphism if + and only if the `rangeRestrict` of `f` is an open quotient map. +* `isStrictMap_prodMap`: The product (in the sense of Prod.map) of strict group homomorphisms +is strict. +-/ + +@[expose] public section + +open Function Set Topology Setoid + +namespace Topology + +variable {X Y Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] + (f : X → Y) {g : Y → Z} + +/-- A map is a strict map in the sense of Bourbaki if the natural map to its image +is a quotient map. -/ +def IsStrictMap : Prop := + IsQuotientMap (Set.rangeFactorization f) + +lemma isStrictMap_iff_isQuotientMap_rangeFactorization : + IsStrictMap f ↔ IsQuotientMap (Set.rangeFactorization f) := + Iff.rfl + +variable {f} + +/-- A map is a strict map if and only if the canonical bijection +`Quotient (Setoid.ker f) ≃ Set.range f` is a homeomorphism. -/ +theorem isStrictMap_iff_isHomeomorph_quotientKerEquivRange : + IsStrictMap f ↔ + IsHomeomorph (Setoid.quotientKerEquivRange f : Quotient (Setoid.ker f) → Set.range f) := by + simp only [IsStrictMap, isHomeomorph_iff_isQuotientMap_injective, Equiv.injective, and_true] + exact ⟨fun h => IsQuotientMap.of_comp_isQuotientMap isQuotientMap_quotient_mk' h, + fun h ↦ h.comp isQuotientMap_quotient_mk'⟩ + +/-- The homeomorphism `Quotient (Setoid.ker f) ≃ₜ Set.range f` given by a strict map `f`. +This is the homeomorphism obtained from the first isomorphism theorem. -/ +noncomputable def Homeomorph.quotientKerEquivRange (hf : IsStrictMap f) : + Quotient (Setoid.ker f) ≃ₜ Set.range f := + (isStrictMap_iff_isHomeomorph_quotientKerEquivRange.mp hf).homeomorph + +/-- A map is a strict map if and only if the canonical injection `Quotient (Setoid.ker f) → Y` +(`Setoid.kerLift f`) is an embedding. -/ +theorem isStrictMap_iff_isEmbedding_kerLift : + IsStrictMap f ↔ IsEmbedding (Setoid.kerLift f) := by + simp only [isStrictMap_iff_isHomeomorph_quotientKerEquivRange, + isHomeomorph_iff_isEmbedding_surjective, Equiv.surjective, and_true] + exact (IsEmbedding.of_comp_iff .subtypeVal).symm + +/-- A strict map is continuous, since the range factorization is continuous. -/ +lemma IsStrictMap.continuous {f : X → Y} (hf : IsStrictMap f) : Continuous f := by + rw [isStrictMap_iff_isQuotientMap_rangeFactorization] at hf + exact continuous_rangeFactorization_iff.mp hf.continuous + +/-- A open continuous map is a strict map. -/ +lemma IsOpenMap.isStrictMap (ho : IsOpenMap f) (h_cont : Continuous f) : + IsStrictMap f := by + rw [isStrictMap_iff_isQuotientMap_rangeFactorization] + exact (ho.subtype_mk fun x => ⟨x, rfl⟩).isQuotientMap + h_cont.rangeFactorization Set.rangeFactorization_surjective + +/-- A closed continuous map is a strict map. -/ +lemma IsClosedMap.isStrictMap (hc : IsClosedMap f) (h_cont : Continuous f) : + IsStrictMap f := by + rw [isStrictMap_iff_isQuotientMap_rangeFactorization] + exact (hc.subtype_mk fun x => ⟨x, rfl⟩).isQuotientMap + h_cont.rangeFactorization Set.rangeFactorization_surjective + +/-- A homeomorphism is a strict map. -/ +lemma IsHomeomorph.isStrictMap (f_homeo : IsHomeomorph f) : + IsStrictMap f := + f_homeo.isOpenMap.isStrictMap f_homeo.continuous + +/-- The identity is a strict map. -/ +lemma IsStrictMap.id : IsStrictMap (id : X → X) := IsHomeomorph.id.isStrictMap + +/-- Assume that `f : X → Y` is a quotient map. Then `g : Y → Z` is strict +if and only if `g ∘ f` is strict. -/ +lemma IsQuotientMap.isStrictMap_iff (f_quot : IsQuotientMap f) : + IsStrictMap g ↔ IsStrictMap (g ∘ f) := by + set Φ : range (g ∘ f) ≃ₜ range g := .setCongr <| f_quot.surjective.range_comp g + have key : rangeFactorization g ∘ f = Φ ∘ rangeFactorization (g ∘ f) := rfl + simp_rw [isStrictMap_iff_isQuotientMap_rangeFactorization, ← f_quot.of_comp_iff, key] + exact ⟨fun H ↦ by simpa using! Φ.symm.isQuotientMap.comp H, fun H ↦ Φ.isQuotientMap.comp H⟩ + +/-- A quotient map is strict. See also `isQuotientMap_iff_isStrictMap_surjective`. -/ +lemma IsQuotientMap.isStrictMap (f_quot : IsQuotientMap f) : + IsStrictMap f := + f_quot.isStrictMap_iff.mp .id + +/-- Assume that `g : Y → Z` is an embedding. Then `f : X → Y` is strict +if and only if `g ∘ f` is strict. -/ +lemma IsEmbedding.isStrictMap_iff (g_emb : IsEmbedding g) : + IsStrictMap f ↔ IsStrictMap (g ∘ f) := by + set Φ : Quotient (Setoid.ker (g ∘ f)) ≃ₜ Quotient (Setoid.ker (f)) := + Homeomorph.Quotient.congrRight (fun _ _ ↦ by simp [g_emb.injective.eq_iff]) + have key : g ∘ kerLift f ∘ Φ = kerLift (g ∘ f) := + funext <| Quotient.ind fun _ ↦ rfl + simp_rw [isStrictMap_iff_isEmbedding_kerLift, ← g_emb.of_comp_iff, ← key] + exact ⟨fun H ↦ H.comp Φ.isEmbedding, + fun H ↦ by simpa [comp_assoc] using H.comp Φ.symm.isEmbedding⟩ + +/-- An embedding is strict. See also `isEmbedding_iff_isStrictMap_injective`. -/ +lemma IsEmbedding.isStrictMap (f_emb : IsEmbedding f) : + IsStrictMap f := + f_emb.isStrictMap_iff.mp .id + +/-- Quotient maps are precisely surjective strict maps. -/ +lemma isQuotientMap_iff_isStrictMap_surjective : + IsQuotientMap f ↔ IsStrictMap f ∧ Surjective f := by + refine ⟨fun H ↦ ⟨H.isStrictMap, H.surjective⟩, fun ⟨f_strict, f_surj⟩ ↦ ?_⟩ + rw [isStrictMap_iff_isQuotientMap_rangeFactorization] at f_strict + set Φ : range f ≃ₜ Y := .trans (.setCongr f_surj.range_eq) (Homeomorph.Set.univ Y) + exact Φ.isQuotientMap.comp f_strict + +/-- Embeddings are precisely injective strict maps. -/ +lemma isEmbedding_iff_isStrictMap_injective : + IsEmbedding f ↔ IsStrictMap f ∧ Injective f := by + refine ⟨fun H ↦ ⟨H.isStrictMap, H.injective⟩, fun ⟨f_strict, f_inj⟩ ↦ ?_⟩ + rw [isStrictMap_iff_isEmbedding_kerLift] at f_strict + set Φ : Quotient (ker f) ≃ₜ X := + (Homeomorph.Quotient.congrRight <| by simp [f_inj.eq_iff]).trans Homeomorph.quotientBot + exact f_strict.comp Φ.symm.isEmbedding + +/-- Strict maps are preserved when precomposing with a homeomorphism. -/ +lemma Homeomorph.isStrictMap_comp_iff (e : X ≃ₜ Y) {f : Y → Z} : + IsStrictMap (f ∘ e) ↔ IsStrictMap f := + e.isQuotientMap.isStrictMap_iff.symm + +/-- Strict maps are preserved when postcomposing with a homeomorphism. -/ +lemma Homeomorph.comp_isStrictMap_iff (e : Y ≃ₜ Z) {f : X → Y} : + IsStrictMap (e ∘ f) ↔ IsStrictMap f := + e.isEmbedding.isStrictMap_iff.symm + +end Topology + +namespace MonoidHom + +variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] (f : G →* H) (g : G' →* H') + [TopologicalSpace G] [IsTopologicalGroup G] [TopologicalSpace H] + +/-- A group homomorphism is strict if and only if its rangeRestrict is an open quotient map. -/ +@[to_additive] lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict : + IsStrictMap f ↔ IsOpenQuotientMap f.rangeRestrict := by + rw [isQuotientMap_iff_isOpenQuotientMap] + rfl + +variable {f g} [TopologicalSpace G'] [IsTopologicalGroup G'] [TopologicalSpace H'] + +/-- The product (in the sense of `Prod.map`) of strict group homomorphisms is strict -/ +@[to_additive isStrictMap_prodMap] lemma isStrictMap_prodMap (hf : IsStrictMap f) (hg : IsStrictMap g) : + IsStrictMap (f.prodMap g) := by + rw [isStrictMap_iff_isOpenQuotientMap_rangeRestrict] at hf hg ⊢ + let aux : (f.prodMap g).range ≃ₜ f.range × g.range := + (Homeomorph.setCongr (by simp [Subgroup.coe_prod])).trans (Homeomorph.Set.prod _ _) + exact aux.symm.isOpenQuotientMap.comp (hf.prodMap hg) + +-- TODO Add the lemma `isStrictMap_piMap` once `MonoidHom.piMap` has been defined. + +end MonoidHom From 3838fb82bf6000581ca0dfca9ff57b9fc656a20b Mon Sep 17 00:00:00 2001 From: zw810-ctrl Date: Tue, 23 Jun 2026 21:59:09 -0400 Subject: [PATCH 142/210] fix --- Mathlib/Topology/Maps/Strict/Basic.lean | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index d646e5eaaf1b93..2f3a2ef8afd581 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -187,14 +187,14 @@ variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] (f : G /-- A group homomorphism is strict if and only if its rangeRestrict is an open quotient map. -/ @[to_additive] lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict : IsStrictMap f ↔ IsOpenQuotientMap f.rangeRestrict := by - rw [isQuotientMap_iff_isOpenQuotientMap] + rw [isOpenQuotientMap_iff_isQuotientMap] rfl variable {f g} [TopologicalSpace G'] [IsTopologicalGroup G'] [TopologicalSpace H'] /-- The product (in the sense of `Prod.map`) of strict group homomorphisms is strict -/ -@[to_additive isStrictMap_prodMap] lemma isStrictMap_prodMap (hf : IsStrictMap f) (hg : IsStrictMap g) : - IsStrictMap (f.prodMap g) := by +@[to_additive isStrictMap_prodMap] lemma isStrictMap_prodMap (hf : IsStrictMap f) + (hg : IsStrictMap g) :IsStrictMap (f.prodMap g) := by rw [isStrictMap_iff_isOpenQuotientMap_rangeRestrict] at hf hg ⊢ let aux : (f.prodMap g).range ≃ₜ f.range × g.range := (Homeomorph.setCongr (by simp [Subgroup.coe_prod])).trans (Homeomorph.Set.prod _ _) From 7c4c6a64c6e0de39f7f61697cec6fe181b2c2f50 Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Wed, 24 Jun 2026 12:04:01 +0200 Subject: [PATCH 143/210] Apply suggestions from code review --- Mathlib/Topology/Maps/Strict/Basic.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index 2f3a2ef8afd581..ec2a2ed345a7a0 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -41,12 +41,12 @@ We provide several equivalent ways to characterize a strict map `f`: In general, the product (in the sense of `Prod.map`) of two strict maps need not be strict. But thanks to `MonoidHom.isOpenQuotientMap_of_isQuotientMap`, we can replace `IsQuotientMap` by `IsOpenQuotientMap` in the setting of group homomorphisms. Therefore we provide several -important properties of a strict group homomorphisms `f` : +important properties of strict group homomorphisms : * `isStrictMap_iff_isOpenQuotientMap_rangeRestrict`: `f` is a strict group homomorphism if and only if the `rangeRestrict` of `f` is an open quotient map. * `isStrictMap_prodMap`: The product (in the sense of Prod.map) of strict group homomorphisms -is strict. + is strict. -/ @[expose] public section @@ -184,7 +184,7 @@ namespace MonoidHom variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] (f : G →* H) (g : G' →* H') [TopologicalSpace G] [IsTopologicalGroup G] [TopologicalSpace H] -/-- A group homomorphism is strict if and only if its rangeRestrict is an open quotient map. -/ +/-- A group homomorphism is strict if and only if its `rangeRestrict` is an open quotient map. -/ @[to_additive] lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict : IsStrictMap f ↔ IsOpenQuotientMap f.rangeRestrict := by rw [isOpenQuotientMap_iff_isQuotientMap] @@ -194,7 +194,7 @@ variable {f g} [TopologicalSpace G'] [IsTopologicalGroup G'] [TopologicalSpace H /-- The product (in the sense of `Prod.map`) of strict group homomorphisms is strict -/ @[to_additive isStrictMap_prodMap] lemma isStrictMap_prodMap (hf : IsStrictMap f) - (hg : IsStrictMap g) :IsStrictMap (f.prodMap g) := by + (hg : IsStrictMap g) : IsStrictMap (f.prodMap g) := by rw [isStrictMap_iff_isOpenQuotientMap_rangeRestrict] at hf hg ⊢ let aux : (f.prodMap g).range ≃ₜ f.range × g.range := (Homeomorph.setCongr (by simp [Subgroup.coe_prod])).trans (Homeomorph.Set.prod _ _) From 642ff7f8a62e8e3789e8ecce856e44546bea7b7e Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Wed, 24 Jun 2026 14:23:50 +0200 Subject: [PATCH 144/210] Update Mathlib/Topology/Maps/OpenQuotient.lean --- Mathlib/Topology/Maps/OpenQuotient.lean | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Mathlib/Topology/Maps/OpenQuotient.lean b/Mathlib/Topology/Maps/OpenQuotient.lean index d6b4d32b35ddca..139d7c8ec14f05 100644 --- a/Mathlib/Topology/Maps/OpenQuotient.lean +++ b/Mathlib/Topology/Maps/OpenQuotient.lean @@ -28,8 +28,7 @@ public section open Filter Function Set Topology -variable {X Y Z W : Type*} [TopologicalSpace X] [TopologicalSpace Y] - [TopologicalSpace Z] [TopologicalSpace W] {f : X → Y} +variable {X Y Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] {f : X → Y} namespace IsOpenQuotientMap From 72350a72391414bde1db4c0debc122952a4be67f Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 25 Jun 2026 11:02:59 +0200 Subject: [PATCH 145/210] Very slight golf --- .../Normed/Operator/Perturbation/StrictByFinite.lean | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 9298a9263c7c13..9e4ab463c667ba 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -107,19 +107,14 @@ theorem step1 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) set Φ : (S × A) ≃L[𝕜] E := prodEquivOfIsTopCompl S A S_compl_A set Ψ : (map u.toLinearMap S × map u.toLinearMap A) ≃L[𝕜] F := prodEquivOfIsTopCompl _ _ uS_compl_uA - -- TODO: after PR #39476 we will be able to use `Φ.symm.isHomeomorph` - have Φ_symm_homeo : IsHomeomorph Φ.symm := Φ.symm.toHomeomorph.isHomeomorph - -- TODO: after PR #39476 we will be able to use `Ψ.isHomeomorph` - have Ψ_homeo : IsHomeomorph Ψ := Ψ.toHomeomorph.isHomeomorph - have uₛ_surj : Surjective uₛ := surjective_mapsTo_image_restrict _ _ - have uₐ_surj : Surjective uₐ := surjective_mapsTo_image_restrict _ _ have u_eq : u = Ψ ∘ (uₛ.prodMap uₐ) ∘ Φ.symm := by ext x simp [Φ, Ψ, uₛ, uₐ, ← map_add, projection_add_projection_eq_self] have u_restr_eq : u.domRestrict A = (map u.toLinearMap A).subtypeL ∘ uₐ := rfl suffices IsStrictMap (uₛ.prodMap uₐ) ↔ IsStrictMap uₐ by rwa [u_restr_eq, u_eq, ← (isEmbedding_subtypeL _).isStrictMap_iff, - ← Ψ_homeo.isEmbedding.isStrictMap_iff, ← Φ_symm_homeo.isQuotientMap.isStrictMap_iff] + ← Ψ.isHomeomorph.isEmbedding.isStrictMap_iff, + ← Φ.symm.isHomeomorph.isQuotientMap.isStrictMap_iff] -- TODO: we should think of a way to avoid this change IsStrictMap (uₛ.toAddMonoidHom.prodMap uₐ.toAddMonoidHom) ↔ IsStrictMap uₐ simp_rw [AddMonoidHom.isStrictMap_prodMap_iff, LinearMap.toAddMonoidHom_coe, coe_coe, From 405a38d370d94311fe4f880785a2c9f7877ef025 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 25 Jun 2026 11:05:50 +0200 Subject: [PATCH 146/210] better comments --- .../Normed/Operator/Perturbation/StrictByFinite.lean | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 9e4ab463c667ba..426c4bbb5273ec 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -68,6 +68,12 @@ We prove the theorem under the assumptions that - `u` is surjective - `u.ker` is disjoint from `A` (i.e. `u` is injective on `A`) - `map u A` is closed + +The strategy of proof is to decompose both spaces into complementary subspace, +with one of the spaces being finite dimensional and `u` preserving this decomposition. + +The result then follows from `AddMonoidHom.isStrictMap_prodMap_iff` and +`ContinuousLinearMap.isStrictMap_of_finiteDimensional`. -/ theorem step1 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) @@ -89,8 +95,8 @@ theorem step1 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) S_compl_A.symm.inf_eq_bot, Submodule.map_bot] · rw [codisjoint_iff, ← Submodule.map_sup, S_compl_A.sup_eq_top, Submodule.map_top, h_range] - -- Because `A` (resp. `map u A`) is closed and `S` (resp `map u S`) is closed, `A` and `S` - -- (resp `map u A` and `map u S`) are in fact *topological* complements of each other. + -- Because `A` (resp. `map u A`) is closed and `S` (resp `map u S`) has finite dimension, + -- `A` and `S` (resp `map u A` and `map u S`) are in fact *topological* complements of each other. replace S_compl_A : IsTopCompl S A := S_compl_A.symm.isTopCompl_of_finiteDimensional_quotient A_closed |>.symm replace uS_compl_uA : IsTopCompl (map u.toLinearMap S) (map u.toLinearMap A) := From f5fce3edb279c0a39f096f7df152b5359806565e Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 25 Jun 2026 14:56:07 +0200 Subject: [PATCH 147/210] feat: characterize when projections are almost 0 or almost id --- .../Algebra/Module/LinearMap/FiniteRange.lean | 24 +++++++++++++++++++ Mathlib/Data/Setoid/Basic.lean | 3 +++ 2 files changed, 27 insertions(+) diff --git a/Mathlib/Algebra/Module/LinearMap/FiniteRange.lean b/Mathlib/Algebra/Module/LinearMap/FiniteRange.lean index a04166c0c38750..dda9a14bbbae04 100644 --- a/Mathlib/Algebra/Module/LinearMap/FiniteRange.lean +++ b/Mathlib/Algebra/Module/LinearMap/FiniteRange.lean @@ -235,6 +235,13 @@ lemma equiv_iff_hasFiniteRange [IsNoetherianRing K] {u v : V →ₗ[K] V₂} : u ≈ v ↔ (u - v).HasFiniteRange := by rw [equiv_iff_hasNoetherianRange, hasNoetherianRange_iff_hasFiniteRange] +lemma equiv_zero_iff_hasNoetherianRange {u : V →ₗ[K] V₂} : u ≈ 0 ↔ u.HasNoetherianRange := by + simp [equiv_iff_hasNoetherianRange] + +lemma equiv_zero_iff_hasFiniteRange [IsNoetherianRing K] {u : V →ₗ[K] V₂} : + u ≈ 0 ↔ u.HasFiniteRange := by + simp [equiv_iff_hasFiniteRange] + lemma equiv_iff_isNoetherian_quotient_eqLocus {u v : V →ₗ[K] V₂} : u ≈ v ↔ IsNoetherian K (V ⧸ eqLocus u v) := by rw [equiv_iff_hasNoetherianRange, hasNoetherianRange_iff_quotient_ker, eqLocus_eq_ker_sub] @@ -269,6 +276,23 @@ lemma equiv_comp {u v : V →ₗ[K] V₂} {u' v' : V₂ →ₗ[K] V₃} (h : u u' ∘ₗ u ≈ v' ∘ₗ v := by grw [equiv_comp_right h', equiv_comp_left h] +lemma projection_equiv_zero_iff_isNoetherian {S T : Submodule K V} (S_compl_T : IsCompl S T) : + S.projection T S_compl_T ≈ 0 ↔ IsNoetherian K S := by + rw [equiv_zero_iff_hasNoetherianRange, hasNoetherianRange_iff_range, range_projection] + +lemma projection_equiv_zero {S T : Submodule K V} [IsNoetherian K S] (S_compl_T : IsCompl S T) : + S.projection T S_compl_T ≈ 0 := + projection_equiv_zero_iff_isNoetherian S_compl_T |>.mpr inferInstance + +lemma projection_equiv_id_iff_isNoetherian {S T : Submodule K V} (S_compl_T : IsCompl S T) : + S.projection T S_compl_T ≈ id ↔ IsNoetherian K T := by + rw [Setoid.comm, equiv_iff_hasNoetherianRange, ← projection_eq_id_sub_projection, + hasNoetherianRange_iff_range, range_projection] + +lemma projection_equiv_id {S T : Submodule K V} [IsNoetherian K T] (S_compl_T : IsCompl S T) : + S.projection T S_compl_T ≈ id := + projection_equiv_id_iff_isNoetherian S_compl_T |>.mpr inferInstance + end FiniteRangeSetoid end Setoid diff --git a/Mathlib/Data/Setoid/Basic.lean b/Mathlib/Data/Setoid/Basic.lean index 29e735ede15619..993671add13f70 100644 --- a/Mathlib/Data/Setoid/Basic.lean +++ b/Mathlib/Data/Setoid/Basic.lean @@ -69,6 +69,9 @@ theorem trans' (r : Setoid α) : ∀ {x y z}, r x y → r y z → r x z := r.ise theorem comm' (s : Setoid α) {x y} : s x y ↔ s y x := ⟨s.symm', s.symm'⟩ +theorem comm [Setoid α] {x y : α} : x ≈ y ↔ y ≈ x := + ⟨Setoid.symm, Setoid.symm⟩ + open scoped Function -- required for scoped `on` notation /-- The kernel of a function is an equivalence relation. -/ From 3408de2f51fd57afd15f666ceec764d764e04010 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 25 Jun 2026 16:59:39 +0200 Subject: [PATCH 148/210] very slight golf --- .../Normed/Operator/Perturbation/StrictByFinite.lean | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 426c4bbb5273ec..f0bc10c4a25945 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -328,14 +328,10 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_quotient [T1Sp let Φ : (F ⧸ A) ≃L[𝕜] S := A.quotientEquivOfIsTopCompl S A_compl_S let i : S →L[𝕜] F := S.subtypeL have i_clemb : IsClosedEmbedding i := S.isClosedEmbedding_subtypeL A_compl_S.symm.isClosed - let p : F →L[𝕜] F := S.projectionL A A_compl_S.symm + set p : F →L[𝕜] F := S.projectionL A A_compl_S.symm with p_def have eq : i ∘ Φ ∘ A.mkQ = p := rfl - -- TODO: The following should be extracted to API about `≈`. - have : .id ≈ p.toLinearMap := by - simp [equiv_iff_hasFiniteRange, p, ← projection_eq_id_sub_projection, LinearMap.HasFiniteRange, - fg_iff_finiteDimensional, dim_A] have : u.toLinearMap ≈ (p ∘L u).toLinearMap := by - grw [toLinearMap_comp, ← this, LinearMap.id_comp] + grw [toLinearMap_comp, p_def, toLinearMap_projectionL, projection_equiv_id, LinearMap.id_comp] calc IsStrictMap u ∧ IsClosed (range u) _ ↔ (IsStrictMap (p ∘ u) ∧ IsClosed (range (p ∘ u))) := ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_finiteRangeSetoid _ _ this From 73c164e3f45f4cfb82e7b5dd4cf794891724be11 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 25 Jun 2026 17:02:07 +0200 Subject: [PATCH 149/210] no more `toHomeomorph` --- .../Normed/Operator/Perturbation/StrictByFinite.lean | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index f0bc10c4a25945..9cd52a58ced298 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -340,7 +340,8 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_quotient [T1Sp _ ↔ (IsStrictMap (Φ ∘ A.mkQ ∘ u) ∧ IsClosed (range (Φ ∘ A.mkQ ∘ u))) := by rw [i_clemb.isStrictMap_iff, i_clemb.isClosed_iff_image_isClosed, ← range_comp] _ ↔ (IsStrictMap (A.mkQ ∘ u) ∧ IsClosed (range (A.mkQ ∘ u))) := by - rw [Φ.toHomeomorph.isEmbedding.isStrictMap_iff, ← Φ.toHomeomorph.isClosed_image, - ← range_comp, Φ.coe_toHomeomorph] + rw [Φ.isHomeomorph.isEmbedding.isStrictMap_iff, + Φ.isHomeomorph.isClosedEmbedding.isClosed_iff_image_isClosed, + ← range_comp] end FiniteDimQuotient From 513ebff7a19b9b47b6229b42a2c4b469c2d3801b Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 30 Jun 2026 11:29:16 +0200 Subject: [PATCH 150/210] add isQuasiInverse_subtype_projectionOnto --- Mathlib/Algebra/Module/LinearMap/FiniteRange.lean | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Mathlib/Algebra/Module/LinearMap/FiniteRange.lean b/Mathlib/Algebra/Module/LinearMap/FiniteRange.lean index dda9a14bbbae04..87b308de3013d4 100644 --- a/Mathlib/Algebra/Module/LinearMap/FiniteRange.lean +++ b/Mathlib/Algebra/Module/LinearMap/FiniteRange.lean @@ -456,6 +456,14 @@ lemma IsQuasiInverse.of_comp_right {u : V →ₗ[K] V₂} {v : V₂ →ₗ[K] V (w ∘ₗ v).IsQuasiInverse u := ⟨hw.1, IsRightQuasiInverse.of_comp_right hv.1 hw.2⟩ +lemma isQuasiInverse_subtype_projectionOnto {S T : Submodule K V} [IsNoetherian K T] + (S_compl_T : IsCompl S T) : + IsQuasiInverse S.subtype (S.projectionOnto T S_compl_T) := by + constructor + · grw [IsLeftQuasiInverse, ← FiniteRangeSetoid.projection_equiv_id S_compl_T] + rfl + · simp [IsRightQuasiInverse, projectionOnto_comp_subtype] + end QuasiInverse end LinearMap From 73a3b8ec53794e51c8325b97e4c402da32a3cd10 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 30 Jun 2026 11:41:27 +0200 Subject: [PATCH 151/210] feat: define Fredholm operators between TVSs --- Mathlib.lean | 1 + .../Algebra/Module/FredholmOperators.lean | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 Mathlib/Topology/Algebra/Module/FredholmOperators.lean diff --git a/Mathlib.lean b/Mathlib.lean index feceaf0c28726e..528d72ba681399 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -7605,6 +7605,7 @@ public import Mathlib.Topology.Algebra.Module.Determinant public import Mathlib.Topology.Algebra.Module.Equiv public import Mathlib.Topology.Algebra.Module.FiniteDimension public import Mathlib.Topology.Algebra.Module.FiniteDimensionBilinear +public import Mathlib.Topology.Algebra.Module.FredholmOperators public import Mathlib.Topology.Algebra.Module.IsWeak public import Mathlib.Topology.Algebra.Module.LinearMap public import Mathlib.Topology.Algebra.Module.LinearMapPiProd diff --git a/Mathlib/Topology/Algebra/Module/FredholmOperators.lean b/Mathlib/Topology/Algebra/Module/FredholmOperators.lean new file mode 100644 index 00000000000000..3e3b1be057a7aa --- /dev/null +++ b/Mathlib/Topology/Algebra/Module/FredholmOperators.lean @@ -0,0 +1,24 @@ +/- +Copyright (c) 2026 Filippo A. E. Nuccio. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jon Bannon, Anatole Dedecker, Patrick Massot, Aaron Liu, Oliver Nash, Filippo A. E. Nuccio +-/ +module + +public import Mathlib.Analysis.Normed.Group.Quotient +public import Mathlib.Analysis.Normed.Module.HahnBanach +public import Mathlib.Analysis.Normed.Operator.Banach +public import Mathlib.Analysis.Normed.Operator.Perturbation.StrictByFinite +public import Mathlib.RingTheory.Finiteness.Cofinite +public import Mathlib.Topology.Algebra.Module.Complement +public import Mathlib.Topology.Algebra.Module.Equiv +public import Mathlib.Topology.Algebra.Module.FiniteDimension +public import Mathlib.Topology.Maps.Strict.Basic +public import Mathlib.Topology.Homeomorph.Defs +public import Mathlib.Algebra.Module.LinearMap.Index +public import Mathlib.Algebra.Module.LinearMap.FiniteRange + +@[expose] public section +noncomputable section FredholmOperators + +end FredholmOperators From 62bd44146030208d9e377ef02793b8ecfc59ff65 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 30 Jun 2026 11:47:33 +0200 Subject: [PATCH 152/210] fix authors --- Mathlib/Topology/Algebra/Module/FredholmOperators.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Topology/Algebra/Module/FredholmOperators.lean b/Mathlib/Topology/Algebra/Module/FredholmOperators.lean index 3e3b1be057a7aa..d420a02ecb6838 100644 --- a/Mathlib/Topology/Algebra/Module/FredholmOperators.lean +++ b/Mathlib/Topology/Algebra/Module/FredholmOperators.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2026 Filippo A. E. Nuccio. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Jon Bannon, Anatole Dedecker, Patrick Massot, Aaron Liu, Oliver Nash, Filippo A. E. Nuccio +Authors: Jon Bannon, Anatole Dedecker, Patrick Massot, Aaron Lin, Oliver Nash, Filippo A. E. Nuccio -/ module From 2d1ae1c4afafb3cb1c287995fada1790d81951f4 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 30 Jun 2026 14:35:14 +0200 Subject: [PATCH 153/210] API skeleton --- Mathlib.lean | 2 +- Mathlib/Analysis/FredholmOperators.lean | 113 ++++++++++++++++++ .../Algebra/Module/FredholmOperators.lean | 24 ---- 3 files changed, 114 insertions(+), 25 deletions(-) create mode 100644 Mathlib/Analysis/FredholmOperators.lean delete mode 100644 Mathlib/Topology/Algebra/Module/FredholmOperators.lean diff --git a/Mathlib.lean b/Mathlib.lean index 5b08bd6d122b99..6326515aa1e917 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2021,6 +2021,7 @@ public import Mathlib.Analysis.Fourier.Notation public import Mathlib.Analysis.Fourier.PoissonSummation public import Mathlib.Analysis.Fourier.RiemannLebesgueLemma public import Mathlib.Analysis.Fourier.ZMod +public import Mathlib.Analysis.FredholmOperators public import Mathlib.Analysis.FunctionalSpaces.SobolevInequality public import Mathlib.Analysis.Hofer public import Mathlib.Analysis.InnerProductSpace.Adjoint @@ -7606,7 +7607,6 @@ public import Mathlib.Topology.Algebra.Module.Determinant public import Mathlib.Topology.Algebra.Module.Equiv public import Mathlib.Topology.Algebra.Module.FiniteDimension public import Mathlib.Topology.Algebra.Module.FiniteDimensionBilinear -public import Mathlib.Topology.Algebra.Module.FredholmOperators public import Mathlib.Topology.Algebra.Module.IsWeak public import Mathlib.Topology.Algebra.Module.LinearMap public import Mathlib.Topology.Algebra.Module.LinearMapPiProd diff --git a/Mathlib/Analysis/FredholmOperators.lean b/Mathlib/Analysis/FredholmOperators.lean new file mode 100644 index 00000000000000..a7f64882f58810 --- /dev/null +++ b/Mathlib/Analysis/FredholmOperators.lean @@ -0,0 +1,113 @@ +/- +Copyright (c) 2026 Filippo A. E. Nuccio. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jon Bannon, Anatole Dedecker, Patrick Massot, Yongxi Lin, Oliver Nash, Filippo A. E. Nuccio +-/ +module + +public import Mathlib.Analysis.Normed.Group.Quotient +public import Mathlib.Analysis.Normed.Module.HahnBanach +public import Mathlib.Analysis.Normed.Operator.Banach +public import Mathlib.Analysis.Normed.Operator.Perturbation.StrictByFinite +public import Mathlib.Algebra.Module.LinearMap.Index + +/-! +# Fredholm operators between topological vector spaces +-/ + +@[expose] public noncomputable section + +open Topology Submodule LinearMap +open LinearMap.FiniteRangeSetoid + +section TVS +namespace ContinuousLinearMap + +variable {𝕜 E F : Type*} [NontriviallyNormedField 𝕜] [AddCommGroup E] [AddCommGroup F] + [Module 𝕜 E] [Module 𝕜 F] [TopologicalSpace E] [TopologicalSpace F] + +/-! +## Definition and equivalent conditions +-/ + +section DefTFAE + +section IsFredholm + +structure IsFredholm (f : E →L[𝕜] F) : Prop where + isStrictMap : IsStrictMap f + isClosed_range : IsClosed (f.range : Set F) + finite_ker : FiniteDimensional 𝕜 f.ker + finite_coker : FiniteDimensional 𝕜 (F ⧸ f.range) + closedComplemented_ker : f.ker.ClosedComplemented + +variable [CompleteSpace 𝕜] [IsTopologicalAddGroup F] [ContinuousSMul 𝕜 F] in +lemma IsFredholm.closedComplemented_range {f : E →L[𝕜] F} (f_fred : IsFredholm f) : + f.range.ClosedComplemented := + have := f_fred.finite_coker + ClosedComplemented.of_finiteDimensional_quotient f_fred.isClosed_range + +end IsFredholm + +section FredholmDecomposition + +variable [ContinuousSub E] + +structure FredholmDecomposition (f : E →L[𝕜] F) where + dom₀ : Submodule 𝕜 E + dom₁ : Submodule 𝕜 E + finite_dom₀ : FiniteDimensional 𝕜 dom₀ + isTopCompl_dom : IsTopCompl dom₀ dom₁ + codom₀ : Submodule 𝕜 F + codom₁ : Submodule 𝕜 F + finite_codom₀ : FiniteDimensional 𝕜 codom₀ + isTopCompl_codom : IsTopCompl codom₀ codom₁ + equiv : dom₁ ≃L[𝕜] codom₁ + eq_equiv' : f = codom₁.subtypeL ∘L equiv ∘L (dom₁.projectionOntoL dom₀ isTopCompl_dom.symm) + +abbrev FredholmDecomposition.domProj {f : E →L[𝕜] F} (dec : FredholmDecomposition f) : + E →L[𝕜] dec.dom₁ := dec.dom₁.projectionOntoL dec.dom₀ dec.isTopCompl_dom.symm + +variable [ContinuousSub F] in +abbrev FredholmDecomposition.codomProj {f : E →L[𝕜] F} (dec : FredholmDecomposition f) : + F →L[𝕜] dec.codom₁ := dec.codom₁.projectionOntoL dec.codom₀ dec.isTopCompl_codom.symm + +lemma FredholmDecomposition.eq_equiv {f : E →L[𝕜] F} (dec : FredholmDecomposition f) : + f = dec.codom₁.subtypeL ∘L dec.equiv ∘L dec.domProj := + dec.eq_equiv' + +lemma FredholmDecomposition.ker_eq {f : E →L[𝕜] F} (dec : FredholmDecomposition f) : + f.ker = dec.dom₀ := by + simp [dec.eq_equiv, ker_comp] + +lemma FredholmDecomposition.range_eq {f : E →L[𝕜] F} (dec : FredholmDecomposition f) : + f.range = dec.codom₁ := by + simp [dec.eq_equiv, range_comp] + +end FredholmDecomposition + +section TFAE + +end TFAE + +variable [IsTopologicalAddGroup E] +-- missing hyps + +theorem isFredholmTFAE (f : E →L[𝕜] F) : List.TFAE + [ + IsFredholm f, + ∃ g : F →L[𝕜] E, g.IsQuasiInverse f, + ∃ (E₁ : Submodule 𝕜 E) (F₁ : Submodule 𝕜 F), + IsClosed (E₁ : Set E) ∧ IsClosed (F₁ : Set F) ∧ + E₁.CoFG ∧ F₁.CoFG ∧ + ∃ h : Set.MapsTo f E₁ F₁, (f.restrict h).IsInvertible, + Nonempty (FredholmDecomposition f) + ] := by + sorry + +end DefTFAE + +end ContinuousLinearMap +end TVS + +end diff --git a/Mathlib/Topology/Algebra/Module/FredholmOperators.lean b/Mathlib/Topology/Algebra/Module/FredholmOperators.lean deleted file mode 100644 index d420a02ecb6838..00000000000000 --- a/Mathlib/Topology/Algebra/Module/FredholmOperators.lean +++ /dev/null @@ -1,24 +0,0 @@ -/- -Copyright (c) 2026 Filippo A. E. Nuccio. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Jon Bannon, Anatole Dedecker, Patrick Massot, Aaron Lin, Oliver Nash, Filippo A. E. Nuccio --/ -module - -public import Mathlib.Analysis.Normed.Group.Quotient -public import Mathlib.Analysis.Normed.Module.HahnBanach -public import Mathlib.Analysis.Normed.Operator.Banach -public import Mathlib.Analysis.Normed.Operator.Perturbation.StrictByFinite -public import Mathlib.RingTheory.Finiteness.Cofinite -public import Mathlib.Topology.Algebra.Module.Complement -public import Mathlib.Topology.Algebra.Module.Equiv -public import Mathlib.Topology.Algebra.Module.FiniteDimension -public import Mathlib.Topology.Maps.Strict.Basic -public import Mathlib.Topology.Homeomorph.Defs -public import Mathlib.Algebra.Module.LinearMap.Index -public import Mathlib.Algebra.Module.LinearMap.FiniteRange - -@[expose] public section -noncomputable section FredholmOperators - -end FredholmOperators From d1b1ebeb2184ddf8794eb9bfa061c333508d2481 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 30 Jun 2026 17:09:12 +0200 Subject: [PATCH 154/210] Progress --- Mathlib/Analysis/FredholmOperators.lean | 115 ++++++++++++++++++------ 1 file changed, 87 insertions(+), 28 deletions(-) diff --git a/Mathlib/Analysis/FredholmOperators.lean b/Mathlib/Analysis/FredholmOperators.lean index a7f64882f58810..7b76c4e6ec83ce 100644 --- a/Mathlib/Analysis/FredholmOperators.lean +++ b/Mathlib/Analysis/FredholmOperators.lean @@ -18,6 +18,7 @@ public import Mathlib.Algebra.Module.LinearMap.Index @[expose] public noncomputable section open Topology Submodule LinearMap +open Set (MapsTo) open LinearMap.FiniteRangeSetoid section TVS @@ -34,18 +35,18 @@ section DefTFAE section IsFredholm -structure IsFredholm (f : E →L[𝕜] F) : Prop where - isStrictMap : IsStrictMap f - isClosed_range : IsClosed (f.range : Set F) - finite_ker : FiniteDimensional 𝕜 f.ker - finite_coker : FiniteDimensional 𝕜 (F ⧸ f.range) - closedComplemented_ker : f.ker.ClosedComplemented +structure IsFredholm (u : E →L[𝕜] F) : Prop where + isStrictMap : IsStrictMap u + isClosed_range : IsClosed (u.range : Set F) + finite_ker : FiniteDimensional 𝕜 u.ker + finite_coker : u.range.CoFG + closedComplemented_ker : u.ker.ClosedComplemented variable [CompleteSpace 𝕜] [IsTopologicalAddGroup F] [ContinuousSMul 𝕜 F] in -lemma IsFredholm.closedComplemented_range {f : E →L[𝕜] F} (f_fred : IsFredholm f) : - f.range.ClosedComplemented := - have := f_fred.finite_coker - ClosedComplemented.of_finiteDimensional_quotient f_fred.isClosed_range +lemma IsFredholm.closedComplemented_range {u : E →L[𝕜] F} (u_fred : IsFredholm u) : + u.range.ClosedComplemented := + have := u_fred.finite_coker + ClosedComplemented.of_finiteDimensional_quotient u_fred.isClosed_range end IsFredholm @@ -53,7 +54,7 @@ section FredholmDecomposition variable [ContinuousSub E] -structure FredholmDecomposition (f : E →L[𝕜] F) where +structure FredholmDecomposition (u : E →L[𝕜] F) where dom₀ : Submodule 𝕜 E dom₁ : Submodule 𝕜 E finite_dom₀ : FiniteDimensional 𝕜 dom₀ @@ -63,25 +64,25 @@ structure FredholmDecomposition (f : E →L[𝕜] F) where finite_codom₀ : FiniteDimensional 𝕜 codom₀ isTopCompl_codom : IsTopCompl codom₀ codom₁ equiv : dom₁ ≃L[𝕜] codom₁ - eq_equiv' : f = codom₁.subtypeL ∘L equiv ∘L (dom₁.projectionOntoL dom₀ isTopCompl_dom.symm) + eq_equiv' : u = codom₁.subtypeL ∘L equiv ∘L (dom₁.projectionOntoL dom₀ isTopCompl_dom.symm) -abbrev FredholmDecomposition.domProj {f : E →L[𝕜] F} (dec : FredholmDecomposition f) : +abbrev FredholmDecomposition.domProj {u : E →L[𝕜] F} (dec : FredholmDecomposition u) : E →L[𝕜] dec.dom₁ := dec.dom₁.projectionOntoL dec.dom₀ dec.isTopCompl_dom.symm variable [ContinuousSub F] in -abbrev FredholmDecomposition.codomProj {f : E →L[𝕜] F} (dec : FredholmDecomposition f) : +abbrev FredholmDecomposition.codomProj {u : E →L[𝕜] F} (dec : FredholmDecomposition u) : F →L[𝕜] dec.codom₁ := dec.codom₁.projectionOntoL dec.codom₀ dec.isTopCompl_codom.symm -lemma FredholmDecomposition.eq_equiv {f : E →L[𝕜] F} (dec : FredholmDecomposition f) : - f = dec.codom₁.subtypeL ∘L dec.equiv ∘L dec.domProj := +lemma FredholmDecomposition.eq_equiv {u : E →L[𝕜] F} (dec : FredholmDecomposition u) : + u = dec.codom₁.subtypeL ∘L dec.equiv ∘L dec.domProj := dec.eq_equiv' -lemma FredholmDecomposition.ker_eq {f : E →L[𝕜] F} (dec : FredholmDecomposition f) : - f.ker = dec.dom₀ := by +lemma FredholmDecomposition.ker_eq {u : E →L[𝕜] F} (dec : FredholmDecomposition u) : + u.ker = dec.dom₀ := by simp [dec.eq_equiv, ker_comp] -lemma FredholmDecomposition.range_eq {f : E →L[𝕜] F} (dec : FredholmDecomposition f) : - f.range = dec.codom₁ := by +lemma FredholmDecomposition.range_eq {u : E →L[𝕜] F} (dec : FredholmDecomposition u) : + u.range = dec.codom₁ := by simp [dec.eq_equiv, range_comp] end FredholmDecomposition @@ -90,19 +91,77 @@ section TFAE end TFAE -variable [IsTopologicalAddGroup E] --- missing hyps - -theorem isFredholmTFAE (f : E →L[𝕜] F) : List.TFAE +variable [T2Space E] [T2Space F] in +private theorem exists_restrict_isInvertible_of_isQuasiInverse {u : E →L[𝕜] F} + {v : F →L[𝕜] E} (huv : v.IsQuasiInverse u) : + ∃ (E₁ : Submodule 𝕜 E) (F₁ : Submodule 𝕜 F), + IsClosed (E₁ : Set E) ∧ IsClosed (F₁ : Set F) ∧ + E₁.CoFG ∧ F₁.CoFG ∧ + ∃ h : MapsTo u E₁ F₁, (u.restrict h).IsInvertible := by + obtain ⟨hvu, huv⟩ := huv + rw [IsLeftQuasiInverse, Setoid.comm, equiv_iff_eqLocus_coFG] at hvu + rw [IsRightQuasiInverse, Setoid.comm, equiv_iff_eqLocus_coFG] at huv + set E₁ := (ContinuousLinearMap.id 𝕜 E).eqLocus (v ∘L u) + set F₁ := (ContinuousLinearMap.id 𝕜 F).eqLocus (u ∘L v) + have u_mapsto : MapsTo u E₁ F₁ := fun x hx ↦ congr(u $hx) + have v_mapsto : MapsTo v F₁ E₁ := fun x hx ↦ congr(v $hx) + refine ⟨E₁, F₁, isClosed_eqLocus _ _, isClosed_eqLocus _ _, hvu, huv, u_mapsto, ?_⟩ + refine .of_inverse (g := v.restrict v_mapsto) ?_ ?_ + · ext ⟨x, hx : x = u (v x)⟩; simp [← hx] + · ext ⟨x, hx : x = v (u x)⟩; simp [← hx] + +variable [CompleteSpace 𝕜] + [IsTopologicalAddGroup E] [ContinuousSMul 𝕜 E] + [IsTopologicalAddGroup F] [ContinuousSMul 𝕜 F] + +variable [T2Space F] in +/-- Assume that `u : E →L[𝕜] F` restricts to an isomorphism between closed finite co-dimension +subspaces `E₁` and `F₁`. Then `u` is Fredholm. + +In fact it is enough to assume that the restriction `E₁ →L[𝕜] F₁` is Fredholm, see +`IsFredholm.of_restrict`. -/ +theorem IsFredholm.of_isInvertible_restrict {u : E →L[𝕜] F} + {E₁ : Submodule 𝕜 E} (E₁_closed : IsClosed (E₁ : Set E)) [E₁_coFG : E₁.CoFG] + {F₁ : Submodule 𝕜 F} (F₁_closed : IsClosed (F₁ : Set F)) [F₁_coFG : F₁.CoFG] + (h_mapsto : MapsTo u E₁ F₁) (h_inv : (u.restrict h_mapsto).IsInvertible) : + IsFredholm u := by + obtain ⟨e, he⟩ := h_inv + have eqL : u.domRestrict E₁ = F₁.subtypeL ∘L e := congr(F₁.subtypeL ∘L $he).symm + have eqₗ : u.toLinearMap.domRestrict E₁ = F₁.subtype ∘ₗ e := congr(($eqL).toLinearMap) + have h : Topology.IsStrictMap u ∧ IsClosed (u.range : Set F) := by + rw [u.isStrictMap_isClosed_range_iff_restrict E₁ E₁_closed, ← LinearMap.range_domRestrict, + eqₗ, eqL] + exact ⟨F₁.isEmbedding_subtype.comp e.isHomeomorph.isEmbedding |>.isStrictMap, by simpa⟩ + have disj : Disjoint E₁ u.ker := by + rw [disjoint_iff_comap_eq_bot, ← LinearMap.ker_domRestrict, eqₗ, + LinearMap.ker_comp, ker_subtype, comap_bot, LinearEquiv.ker] + constructor + · exact h.1 + · exact h.2 + · rw [← Submodule.fg_iff_finiteDimensional] + exact E₁_coFG.fg_of_disjoint disj.symm + · refine F₁_coFG.of_le (le_trans ?_ (u.range_domRestrict_le_range E₁)) + rw [eqₗ, LinearMap.range_comp, LinearEquiv.range, Submodule.map_top, range_subtype] + · exact .of_disjoint_of_finiteDimensional_quotient E₁_closed disj.symm + +variable [T2Space E] [T2Space F] + +theorem isFredholmTFAE (u : E →L[𝕜] F) : List.TFAE [ - IsFredholm f, - ∃ g : F →L[𝕜] E, g.IsQuasiInverse f, + IsFredholm u, + ∃ v : F →L[𝕜] E, v.IsQuasiInverse u, ∃ (E₁ : Submodule 𝕜 E) (F₁ : Submodule 𝕜 F), IsClosed (E₁ : Set E) ∧ IsClosed (F₁ : Set F) ∧ E₁.CoFG ∧ F₁.CoFG ∧ - ∃ h : Set.MapsTo f E₁ F₁, (f.restrict h).IsInvertible, - Nonempty (FredholmDecomposition f) + ∃ h : MapsTo u E₁ F₁, (u.restrict h).IsInvertible, + Nonempty (FredholmDecomposition u) ] := by + tfae_have 3 → 1 := by + rintro ⟨E₁, F₁, E₁_closed, F₁_closed, E₁_coFG, F₁_coFG, u_mapsto, u_invertible⟩ + exact .of_isInvertible_restrict E₁_closed F₁_closed u_mapsto u_invertible + tfae_have 2 → 3 := by + rintro ⟨v, huv⟩ + exact exists_restrict_isInvertible_of_isQuasiInverse huv sorry end DefTFAE From aac12eaf7546b74f2356f9d1adb33b973499a1fc Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 30 Jun 2026 19:40:21 +0200 Subject: [PATCH 155/210] Almost done! --- Mathlib/Algebra/Module/Submodule/Ker.lean | 4 +- Mathlib/Analysis/FredholmOperators.lean | 95 ++++++++++++++++++++--- Mathlib/Topology/Maps/Strict/Basic.lean | 6 ++ 3 files changed, 94 insertions(+), 11 deletions(-) diff --git a/Mathlib/Algebra/Module/Submodule/Ker.lean b/Mathlib/Algebra/Module/Submodule/Ker.lean index 876ecf85efa630..7e25f3a4c076f5 100644 --- a/Mathlib/Algebra/Module/Submodule/Ker.lean +++ b/Mathlib/Algebra/Module/Submodule/Ker.lean @@ -209,8 +209,8 @@ alias _root_.LinearMapClass.ker_eq_bot := ker_eq_bot rw [h] at this simpa [mk_eq_zero] using this -@[simp] theorem injective_restrict_iff_disjoint {p : Submodule R M} {f : M →ₗ[R] M} - (hf : ∀ x ∈ p, f x ∈ p) : +@[simp] theorem injective_restrict_iff_disjoint {p : Submodule R M} {q : Submodule R₂ M₂} + {f : M →ₛₗ[τ₁₂] M₂} (hf : ∀ x ∈ p, f x ∈ q) : Injective (f.restrict hf) ↔ Disjoint p (ker f) := by rw [← ker_eq_bot, ker_restrict hf, ← ker_domRestrict, ker_eq_bot, injective_domRestrict_iff, disjoint_iff] diff --git a/Mathlib/Analysis/FredholmOperators.lean b/Mathlib/Analysis/FredholmOperators.lean index 7b76c4e6ec83ce..9e7ac1fd845e15 100644 --- a/Mathlib/Analysis/FredholmOperators.lean +++ b/Mathlib/Analysis/FredholmOperators.lean @@ -85,6 +85,27 @@ lemma FredholmDecomposition.range_eq {u : E →L[𝕜] F} (dec : FredholmDecompo u.range = dec.codom₁ := by simp [dec.eq_equiv, range_comp] +variable [ContinuousSub F] in +def FredholmDecomposition.quasiInverse {u : E →L[𝕜] F} (dec : FredholmDecomposition u) : + F →L[𝕜] E := + dec.dom₁.subtypeL ∘L dec.equiv.symm ∘L dec.codomProj + +variable [ContinuousSub F] in +lemma FredholmDecomposition.isQuasiInverse {u : E →L[𝕜] F} (dec : FredholmDecomposition u) : + u.IsQuasiInverse dec.quasiInverse := by + nth_rw 1 [dec.eq_equiv, quasiInverse] + have hdom : IsQuasiInverse dec.dom₁.subtype dec.domProj := + have := dec.finite_dom₀ + isQuasiInverse_subtype_projectionOnto _ + have hcodom : IsQuasiInverse dec.codom₁.subtype dec.codomProj := + have := dec.finite_codom₀ + isQuasiInverse_subtype_projectionOnto _ + refine .of_comp_left hcodom.symm <| .of_comp_right hdom ?_ + simp_rw [domProj, codomProj, toLinearMap_comp, toLinearMap_subtypeL, toLinearMap_projectionOntoL, + LinearMap.comp_assoc, projectionOnto_comp_subtype, LinearMap.comp_id, + ← LinearMap.comp_assoc, projectionOnto_comp_subtype, LinearMap.id_comp] + simp [IsQuasiInverse, IsLeftQuasiInverse, IsRightQuasiInverse] + end FredholmDecomposition section TFAE @@ -93,14 +114,14 @@ end TFAE variable [T2Space E] [T2Space F] in private theorem exists_restrict_isInvertible_of_isQuasiInverse {u : E →L[𝕜] F} - {v : F →L[𝕜] E} (huv : v.IsQuasiInverse u) : + {v : F →L[𝕜] E} (huv : u.IsQuasiInverse v) : ∃ (E₁ : Submodule 𝕜 E) (F₁ : Submodule 𝕜 F), IsClosed (E₁ : Set E) ∧ IsClosed (F₁ : Set F) ∧ E₁.CoFG ∧ F₁.CoFG ∧ ∃ h : MapsTo u E₁ F₁, (u.restrict h).IsInvertible := by - obtain ⟨hvu, huv⟩ := huv - rw [IsLeftQuasiInverse, Setoid.comm, equiv_iff_eqLocus_coFG] at hvu - rw [IsRightQuasiInverse, Setoid.comm, equiv_iff_eqLocus_coFG] at huv + obtain ⟨huv, hvu⟩ := huv + rw [IsLeftQuasiInverse, Setoid.comm, equiv_iff_eqLocus_coFG] at huv + rw [IsRightQuasiInverse, Setoid.comm, equiv_iff_eqLocus_coFG] at hvu set E₁ := (ContinuousLinearMap.id 𝕜 E).eqLocus (v ∘L u) set F₁ := (ContinuousLinearMap.id 𝕜 F).eqLocus (u ∘L v) have u_mapsto : MapsTo u E₁ F₁ := fun x hx ↦ congr(u $hx) @@ -144,25 +165,81 @@ theorem IsFredholm.of_isInvertible_restrict {u : E →L[𝕜] F} rw [eqₗ, LinearMap.range_comp, LinearEquiv.range, Submodule.map_top, range_subtype] · exact .of_disjoint_of_finiteDimensional_quotient E₁_closed disj.symm +def IsFredholm.fredholmDecomposition_of_isTopCompl {u : E →L[𝕜] F} + (u_fred : IsFredholm u) {dom₁ : Submodule 𝕜 E} {codom₀ : Submodule 𝕜 F} + (h_dom : IsTopCompl u.ker dom₁) (h_codom : IsTopCompl codom₀ u.range) : + FredholmDecomposition u := + haveI u_mapsto : MapsTo u dom₁ u.range := Set.mapsTo_range _ _ + haveI uₗ_mapsto : MapsTo u.toLinearMap dom₁ u.range := u_mapsto + haveI u_eq_u_restr : u = u.range.subtypeL ∘L u.restrict u_mapsto ∘L + dom₁.projectionOntoL u.ker h_dom.symm := by + refine LinearMap.ext_on_codisjoint h_dom.isCompl.codisjoint ?_ ?_ + · intro x (hx : u x = 0) + simp [hx, projection_apply_of_mem_right] + · intro x (hx : x ∈ dom₁) + simp [hx, projection_apply_of_mem_left] + haveI u_restr_isHomeo : IsHomeomorph (u.restrict u_mapsto) := by + rw [isHomeomorph_iff_isStrictMap_bijective] + constructor + · rw [u.range.isEmbedding_subtypeL.isStrictMap_iff, ← coe_comp, + (isQuotientMap_projectionOntoL h_dom.symm).isStrictMap_iff, ← coe_comp, + comp_assoc, ← u_eq_u_restr] + exact u_fred.isStrictMap + · constructor + · rw [← coe_coe, toLinearMap_restrict] + sorry -- rw [u.toLinearMap.injective_restrict_iff_disjoint uₗ_mapsto] + · sorry + { dom₀ := u.ker + dom₁ := dom₁ + finite_dom₀ := u_fred.finite_ker + isTopCompl_dom := h_dom + codom₀ := codom₀ + codom₁ := u.range + finite_codom₀ := Module.Finite.of_fg <| u_fred.finite_coker.fg_of_isCompl h_codom.isCompl.symm + isTopCompl_codom := h_codom + equiv := + haveI u_mapsto : MapsTo u dom₁ u.range := Set.mapsTo_range _ _ + haveI u_restr_isHomeo : IsHomeomorph (u.restrict u_mapsto) := by + rw [isHomeomorph_iff_isStrictMap_bijective] + constructor + · rw [u.range.isEmbedding_subtypeL.isStrictMap_iff, ← coe_comp, + (isQuotientMap_projectionOntoL h_dom.symm).isStrictMap_iff, ← coe_comp] + simpa [comp_assoc, subtypeL_comp_restrict] using u_fred.isStrictMap + sorry + · sorry + .ofIsHomeomorph (.ofBijective _ u_restr_isHomeo.bijective) u_restr_isHomeo + eq_equiv' := by + refine LinearMap.ext_on_codisjoint h_dom.isCompl.codisjoint ?_ ?_ + · intro x (hx : u x = 0) + simp [hx, projection_apply_of_mem_right] + · intro x (hx : x ∈ dom₁) + simp [hx, projection_apply_of_mem_left] } + + variable [T2Space E] [T2Space F] theorem isFredholmTFAE (u : E →L[𝕜] F) : List.TFAE [ IsFredholm u, - ∃ v : F →L[𝕜] E, v.IsQuasiInverse u, + ∃ v : F →L[𝕜] E, u.IsQuasiInverse v, ∃ (E₁ : Submodule 𝕜 E) (F₁ : Submodule 𝕜 F), IsClosed (E₁ : Set E) ∧ IsClosed (F₁ : Set F) ∧ E₁.CoFG ∧ F₁.CoFG ∧ ∃ h : MapsTo u E₁ F₁, (u.restrict h).IsInvertible, Nonempty (FredholmDecomposition u) ] := by - tfae_have 3 → 1 := by - rintro ⟨E₁, F₁, E₁_closed, F₁_closed, E₁_coFG, F₁_coFG, u_mapsto, u_invertible⟩ - exact .of_isInvertible_restrict E₁_closed F₁_closed u_mapsto u_invertible + tfae_have 1 → 4 := by + sorry + tfae_have 4 → 2 := by + rintro ⟨dec⟩ + exact ⟨dec.quasiInverse, dec.isQuasiInverse⟩ tfae_have 2 → 3 := by rintro ⟨v, huv⟩ exact exists_restrict_isInvertible_of_isQuasiInverse huv - sorry + tfae_have 3 → 1 := by + rintro ⟨E₁, F₁, E₁_closed, F₁_closed, E₁_coFG, F₁_coFG, u_mapsto, u_invertible⟩ + exact .of_isInvertible_restrict E₁_closed F₁_closed u_mapsto u_invertible + tfae_finish end DefTFAE diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index 91558107ed066b..df5a1e96472a03 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -167,6 +167,12 @@ lemma isEmbedding_iff_isStrictMap_injective : (Homeomorph.Quotient.congrRight <| by simp [f_inj.eq_iff]).trans Homeomorph.quotientBot exact f_strict.comp Φ.symm.isEmbedding +/-- Homeomorphisms are precisely bijective strict maps. -/ +lemma isHomeomorph_iff_isStrictMap_bijective : + IsHomeomorph f ↔ IsStrictMap f ∧ Bijective f := by + simp [isHomeomorph_iff_isEmbedding_surjective, isEmbedding_iff_isStrictMap_injective, Bijective, + and_assoc] + /-- Strict maps are preserved when precomposing with a homeomorphism. -/ lemma Homeomorph.isStrictMap_comp_iff (e : X ≃ₜ Y) {f : Y → Z} : IsStrictMap (f ∘ e) ↔ IsStrictMap f := From 3dd87e7e884f4b26905085d8edd90c9cd655b0d7 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 30 Jun 2026 22:49:25 +0200 Subject: [PATCH 156/210] rename --- Mathlib.lean | 2 +- .../Analysis/{FredholmOperators.lean => FredholmOperator.lean} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename Mathlib/Analysis/{FredholmOperators.lean => FredholmOperator.lean} (100%) diff --git a/Mathlib.lean b/Mathlib.lean index 6326515aa1e917..58d1c67e4d8ba7 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -2021,7 +2021,7 @@ public import Mathlib.Analysis.Fourier.Notation public import Mathlib.Analysis.Fourier.PoissonSummation public import Mathlib.Analysis.Fourier.RiemannLebesgueLemma public import Mathlib.Analysis.Fourier.ZMod -public import Mathlib.Analysis.FredholmOperators +public import Mathlib.Analysis.FredholmOperator public import Mathlib.Analysis.FunctionalSpaces.SobolevInequality public import Mathlib.Analysis.Hofer public import Mathlib.Analysis.InnerProductSpace.Adjoint diff --git a/Mathlib/Analysis/FredholmOperators.lean b/Mathlib/Analysis/FredholmOperator.lean similarity index 100% rename from Mathlib/Analysis/FredholmOperators.lean rename to Mathlib/Analysis/FredholmOperator.lean From 3c79ac2682b065d02d1b0980f08e1fee901c624b Mon Sep 17 00:00:00 2001 From: ADedecker Date: Tue, 30 Jun 2026 23:47:42 +0200 Subject: [PATCH 157/210] TFAE done --- Mathlib/Analysis/FredholmOperator.lean | 36 +++++++++++--------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index 9e7ac1fd845e15..e36aae9737e9ba 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -165,7 +165,8 @@ theorem IsFredholm.of_isInvertible_restrict {u : E →L[𝕜] F} rw [eqₗ, LinearMap.range_comp, LinearEquiv.range, Submodule.map_top, range_subtype] · exact .of_disjoint_of_finiteDimensional_quotient E₁_closed disj.symm -def IsFredholm.fredholmDecomposition_of_isTopCompl {u : E →L[𝕜] F} +omit [ContinuousSMul 𝕜 E] in +def IsFredholm.fredholmDecomposition {u : E →L[𝕜] F} (u_fred : IsFredholm u) {dom₁ : Submodule 𝕜 E} {codom₀ : Submodule 𝕜 F} (h_dom : IsTopCompl u.ker dom₁) (h_codom : IsTopCompl codom₀ u.range) : FredholmDecomposition u := @@ -179,6 +180,7 @@ def IsFredholm.fredholmDecomposition_of_isTopCompl {u : E →L[𝕜] F} · intro x (hx : x ∈ dom₁) simp [hx, projection_apply_of_mem_left] haveI u_restr_isHomeo : IsHomeomorph (u.restrict u_mapsto) := by + -- This is a bit messy rw [isHomeomorph_iff_isStrictMap_bijective] constructor · rw [u.range.isEmbedding_subtypeL.isStrictMap_iff, ← coe_comp, @@ -186,9 +188,10 @@ def IsFredholm.fredholmDecomposition_of_isTopCompl {u : E →L[𝕜] F} comp_assoc, ← u_eq_u_restr] exact u_fred.isStrictMap · constructor - · rw [← coe_coe, toLinearMap_restrict] - sorry -- rw [u.toLinearMap.injective_restrict_iff_disjoint uₗ_mapsto] - · sorry + · simpa [← coe_coe, injective_restrict_iff_disjoint] using h_dom.isCompl.symm.disjoint + · suffices u.range ≤ map u.toLinearMap dom₁ by simpa [← coe_coe, ← LinearMap.range_eq_top] + simpa [← Submodule.map_top, Submodule.map_le_iff_le_comap, Submodule.comap_map_eq] + using h_dom.isCompl.symm.sup_eq_top { dom₀ := u.ker dom₁ := dom₁ finite_dom₀ := u_fred.finite_ker @@ -198,23 +201,15 @@ def IsFredholm.fredholmDecomposition_of_isTopCompl {u : E →L[𝕜] F} finite_codom₀ := Module.Finite.of_fg <| u_fred.finite_coker.fg_of_isCompl h_codom.isCompl.symm isTopCompl_codom := h_codom equiv := - haveI u_mapsto : MapsTo u dom₁ u.range := Set.mapsTo_range _ _ - haveI u_restr_isHomeo : IsHomeomorph (u.restrict u_mapsto) := by - rw [isHomeomorph_iff_isStrictMap_bijective] - constructor - · rw [u.range.isEmbedding_subtypeL.isStrictMap_iff, ← coe_comp, - (isQuotientMap_projectionOntoL h_dom.symm).isStrictMap_iff, ← coe_comp] - simpa [comp_assoc, subtypeL_comp_restrict] using u_fred.isStrictMap - sorry - · sorry .ofIsHomeomorph (.ofBijective _ u_restr_isHomeo.bijective) u_restr_isHomeo - eq_equiv' := by - refine LinearMap.ext_on_codisjoint h_dom.isCompl.codisjoint ?_ ?_ - · intro x (hx : u x = 0) - simp [hx, projection_apply_of_mem_right] - · intro x (hx : x ∈ dom₁) - simp [hx, projection_apply_of_mem_left] } + eq_equiv' := u_eq_u_restr } +omit [ContinuousSMul 𝕜 E] in +theorem IsFredholm.nonempty_fredholmDecomposition {u : E →L[𝕜] F} + (u_fred : IsFredholm u) : Nonempty (FredholmDecomposition u) := by + obtain ⟨codom₀, h_codom⟩ := u_fred.closedComplemented_range.exists_isTopCompl + obtain ⟨dom₁, h_dom⟩ := u_fred.closedComplemented_ker.exists_isTopCompl + exact ⟨u_fred.fredholmDecomposition h_dom h_codom.symm⟩ variable [T2Space E] [T2Space F] @@ -228,8 +223,7 @@ theorem isFredholmTFAE (u : E →L[𝕜] F) : List.TFAE ∃ h : MapsTo u E₁ F₁, (u.restrict h).IsInvertible, Nonempty (FredholmDecomposition u) ] := by - tfae_have 1 → 4 := by - sorry + tfae_have 1 → 4 := IsFredholm.nonempty_fredholmDecomposition tfae_have 4 → 2 := by rintro ⟨dec⟩ exact ⟨dec.quasiInverse, dec.isQuasiInverse⟩ From 6d85fe77acdd369ee47759522f81c3d2fa1ff409 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 1 Jul 2026 10:57:33 +0200 Subject: [PATCH 158/210] chore: cleanup API around LinearMap.injective_domRestrict_iff --- Mathlib/Algebra/Module/Submodule/Ker.lean | 32 +++++++++---------- .../FiniteDimensional/Basic.lean | 2 +- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/Mathlib/Algebra/Module/Submodule/Ker.lean b/Mathlib/Algebra/Module/Submodule/Ker.lean index 876ecf85efa630..d052a15cceb08c 100644 --- a/Mathlib/Algebra/Module/Submodule/Ker.lean +++ b/Mathlib/Algebra/Module/Submodule/Ker.lean @@ -197,23 +197,21 @@ theorem ker_eq_bot {f : M →ₛₗ[τ₁₂] M₂} : ker f = ⊥ ↔ Injective alias _root_.LinearMapClass.ker_eq_bot := ker_eq_bot @[simp] lemma injective_domRestrict_iff {f : M →ₛₗ[τ₁₂] M₂} {S : Submodule R M} : - Injective (f.domRestrict S) ↔ S ⊓ LinearMap.ker f = ⊥ := by - rw [← LinearMap.ker_eq_bot] - refine ⟨fun h ↦ le_bot_iff.1 ?_, fun h ↦ le_bot_iff.1 ?_⟩ - · intro x ⟨hx, h'x⟩ - have : ⟨x, hx⟩ ∈ LinearMap.ker (LinearMap.domRestrict f S) := by simpa using h'x - rw [h] at this - simpa [mk_eq_zero] using this - · rintro ⟨x, hx⟩ h'x - have : x ∈ S ⊓ LinearMap.ker f := ⟨hx, h'x⟩ - rw [h] at this - simpa [mk_eq_zero] using this - -@[simp] theorem injective_restrict_iff_disjoint {p : Submodule R M} {f : M →ₗ[R] M} - (hf : ∀ x ∈ p, f x ∈ p) : - Injective (f.restrict hf) ↔ Disjoint p (ker f) := by - rw [← ker_eq_bot, ker_restrict hf, ← ker_domRestrict, ker_eq_bot, injective_domRestrict_iff, - disjoint_iff] + Injective (f.domRestrict S) ↔ Disjoint S f.ker := by + simp [← ker_eq_bot, ker_domRestrict, disjoint_iff_comap_eq_bot] + +@[simp] +theorem injective_restrict_iff {p : Submodule R M} {q : Submodule R₂ M₂} {f : M →ₛₗ[τ₁₂] M₂} + (hf : ∀ x ∈ p, f x ∈ q) : Injective (f.restrict hf) ↔ Disjoint p (ker f) := by + simp [← ker_eq_bot, ker_restrict, disjoint_iff_comap_eq_bot] + +@[deprecated (since := "2026-07-01")] +alias injective_restrict_iff_disjoint := injective_restrict_iff + +@[simp] +theorem injective_codRestrict_iff {q : Submodule R₂ M₂} {f : M →ₛₗ[τ₁₂] M₂} + (hf : ∀ x, f x ∈ q) : Injective (f.codRestrict q hf) ↔ Injective f := + Set.injective_codRestrict _ end Ring diff --git a/Mathlib/LinearAlgebra/FiniteDimensional/Basic.lean b/Mathlib/LinearAlgebra/FiniteDimensional/Basic.lean index ce0aff98a36521..93b0329b07dafe 100644 --- a/Mathlib/LinearAlgebra/FiniteDimensional/Basic.lean +++ b/Mathlib/LinearAlgebra/FiniteDimensional/Basic.lean @@ -383,7 +383,7 @@ theorem comap_eq_sup_ker_of_disjoint {p : Submodule K V} [FiniteDimensional K p] p.comap f = p ⊔ ker f := by refine le_antisymm (fun x hx ↦ ?_) (sup_le_iff.mpr ⟨h, ker_le_comap _⟩) obtain ⟨⟨y, hy⟩, hxy⟩ := - surjective_of_injective ((injective_restrict_iff_disjoint h).mpr h') ⟨f x, hx⟩ + surjective_of_injective ((injective_restrict_iff h).mpr h') ⟨f x, hx⟩ replace hxy : f y = f x := by simpa [Subtype.ext_iff] using hxy exact Submodule.mem_sup.mpr ⟨y, hy, x - y, by simp [hxy], add_sub_cancel y x⟩ From b02d082f4495dd0bc16857f87f4daffae83d999b Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 1 Jul 2026 11:18:50 +0200 Subject: [PATCH 159/210] fix1 --- Mathlib/RingTheory/Noetherian/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/RingTheory/Noetherian/Basic.lean b/Mathlib/RingTheory/Noetherian/Basic.lean index 324118d0f9e31a..e2457ce2c3363d 100644 --- a/Mathlib/RingTheory/Noetherian/Basic.lean +++ b/Mathlib/RingTheory/Noetherian/Basic.lean @@ -386,7 +386,7 @@ lemma FG.of_le [IsNoetherianRing R] {S T : Submodule R M} (hT : T.FG) (hST : S See also `Submodule.CoFG.fg_of_disjoint`. -/ theorem FG.of_disjoint_of_isNoetherian_quotient {S T : Submodule R M} [IsNoetherian R (M ⧸ T)] (hST : Disjoint S T) : S.FG := - Module.Finite.iff_fg.mp <| .of_injective (T.mkQ.domRestrict S) (by simp [hST.eq_bot]) + Module.Finite.iff_fg.mp <| .of_injective (T.mkQ.domRestrict S) (by simp [hST]) end Submodule From e42dc37d5a1e81bde5dd8183185a287dd3ff4c1b Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 1 Jul 2026 11:20:03 +0200 Subject: [PATCH 160/210] fix2 --- Mathlib/LinearAlgebra/Dimension/RankNullity.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/LinearAlgebra/Dimension/RankNullity.lean b/Mathlib/LinearAlgebra/Dimension/RankNullity.lean index 9f6f1ba0053b2f..1d820f2b0b100c 100644 --- a/Mathlib/LinearAlgebra/Dimension/RankNullity.lean +++ b/Mathlib/LinearAlgebra/Dimension/RankNullity.lean @@ -260,7 +260,7 @@ lemma Submodule.disjoint_ker_of_finrank_le [IsDomain R] [IsTorsionFree R M] {N : [AddCommGroup N] [Module R N] {L : Submodule R M} [Module.Finite R L] (f : M →ₗ[R] N) (h : finrank R L ≤ finrank R (L.map f)) : Disjoint L (LinearMap.ker f) := by - refine disjoint_iff.mpr <| LinearMap.injective_domRestrict_iff.mp <| LinearMap.ker_eq_bot.mp <| + refine LinearMap.injective_domRestrict_iff.mp <| LinearMap.ker_eq_bot.mp <| Submodule.rank_eq_zero.mp ?_ rw [← Submodule.finrank_eq_rank, Nat.cast_eq_zero] rw [← LinearMap.range_domRestrict] at h From 007b42b9348d0cee681bdb5c2ed80e7bb4317d86 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 1 Jul 2026 11:30:27 +0200 Subject: [PATCH 161/210] fix3 --- Mathlib/MeasureTheory/Measure/Haar/Disintegration.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/MeasureTheory/Measure/Haar/Disintegration.lean b/Mathlib/MeasureTheory/Measure/Haar/Disintegration.lean index 210f423f434634..9b78d48bf1a3ff 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/Disintegration.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/Disintegration.lean @@ -63,7 +63,7 @@ theorem LinearMap.exists_map_addHaar_eq_smul_addHaar' (h : Function.Surjective L let P : S × T →ₗ[𝕜] T := LinearMap.snd 𝕜 S T have P_cont : Continuous P := LinearMap.continuous_of_finiteDimensional _ have I : Function.Bijective (LinearMap.domRestrict L T) := - ⟨LinearMap.injective_domRestrict_iff.2 (IsCompl.inf_eq_bot hT.symm), + ⟨LinearMap.injective_domRestrict_iff.2 hT.disjoint.symm, (LinearMap.surjective_domRestrict_iff h).2 hT.symm.sup_eq_top⟩ let L' : T ≃ₗ[𝕜] F := LinearEquiv.ofBijective (LinearMap.domRestrict L T) I have L'_cont : Continuous L' := LinearMap.continuous_of_finiteDimensional _ From 7f774777bce4efa5269ff64a8415389d2866a018 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 1 Jul 2026 14:35:47 +0200 Subject: [PATCH 162/210] feat: more API specific to strict group homs --- Mathlib.lean | 1 + Mathlib/Topology/Maps/Strict/Basic.lean | 48 +++------------ Mathlib/Topology/Maps/Strict/Group.lean | 77 +++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 40 deletions(-) create mode 100644 Mathlib/Topology/Maps/Strict/Group.lean diff --git a/Mathlib.lean b/Mathlib.lean index ff49b998f216bb..907d5cff55352b 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -7951,6 +7951,7 @@ public import Mathlib.Topology.Maps.Proper.Basic public import Mathlib.Topology.Maps.Proper.CompactlyGenerated public import Mathlib.Topology.Maps.Proper.UniversallyClosed public import Mathlib.Topology.Maps.Strict.Basic +public import Mathlib.Topology.Maps.Strict.Group public import Mathlib.Topology.MetricSpace.Algebra public import Mathlib.Topology.MetricSpace.Antilipschitz public import Mathlib.Topology.MetricSpace.Basic diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index df5a1e96472a03..71113fae5323f7 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -63,12 +63,12 @@ is a quotient map. -/ def IsStrictMap : Prop := IsQuotientMap (Set.rangeFactorization f) +variable {f} + lemma isStrictMap_iff_isQuotientMap_rangeFactorization : IsStrictMap f ↔ IsQuotientMap (Set.rangeFactorization f) := Iff.rfl -variable {f} - /-- A map is a strict map if and only if the canonical bijection `Quotient (Setoid.ker f) ≃ Set.range f` is a homeomorphism. -/ theorem isStrictMap_iff_isHomeomorph_quotientKerEquivRange : @@ -80,7 +80,7 @@ theorem isStrictMap_iff_isHomeomorph_quotientKerEquivRange : /-- The homeomorphism `Quotient (Setoid.ker f) ≃ₜ Set.range f` given by a strict map `f`. This is the homeomorphism obtained from the first isomorphism theorem. -/ -noncomputable def Homeomorph.quotientKerEquivRange (hf : IsStrictMap f) : +noncomputable def _root_.Homeomorph.quotientKerEquivRange (hf : IsStrictMap f) : Quotient (Setoid.ker f) ≃ₜ Set.range f := (isStrictMap_iff_isHomeomorph_quotientKerEquivRange.mp hf).homeomorph @@ -98,21 +98,21 @@ lemma IsStrictMap.continuous {f : X → Y} (hf : IsStrictMap f) : Continuous f : exact continuous_rangeFactorization_iff.mp hf.continuous /-- A open continuous map is a strict map. -/ -lemma IsOpenMap.isStrictMap (ho : IsOpenMap f) (h_cont : Continuous f) : +lemma _root_.IsOpenMap.isStrictMap (ho : IsOpenMap f) (h_cont : Continuous f) : IsStrictMap f := by rw [isStrictMap_iff_isQuotientMap_rangeFactorization] exact (ho.subtype_mk fun x => ⟨x, rfl⟩).isQuotientMap h_cont.rangeFactorization Set.rangeFactorization_surjective /-- A closed continuous map is a strict map. -/ -lemma IsClosedMap.isStrictMap (hc : IsClosedMap f) (h_cont : Continuous f) : +lemma _root_.IsClosedMap.isStrictMap (hc : IsClosedMap f) (h_cont : Continuous f) : IsStrictMap f := by rw [isStrictMap_iff_isQuotientMap_rangeFactorization] exact (hc.subtype_mk fun x => ⟨x, rfl⟩).isQuotientMap h_cont.rangeFactorization Set.rangeFactorization_surjective /-- A homeomorphism is a strict map. -/ -lemma IsHomeomorph.isStrictMap (f_homeo : IsHomeomorph f) : +lemma _root_.IsHomeomorph.isStrictMap (f_homeo : IsHomeomorph f) : IsStrictMap f := f_homeo.isOpenMap.isStrictMap f_homeo.continuous @@ -174,45 +174,13 @@ lemma isHomeomorph_iff_isStrictMap_bijective : and_assoc] /-- Strict maps are preserved when precomposing with a homeomorphism. -/ -lemma Homeomorph.isStrictMap_comp_iff (e : X ≃ₜ Y) {f : Y → Z} : +lemma _root_.Homeomorph.isStrictMap_comp_iff (e : X ≃ₜ Y) {f : Y → Z} : IsStrictMap (f ∘ e) ↔ IsStrictMap f := e.isQuotientMap.isStrictMap_iff.symm /-- Strict maps are preserved when postcomposing with a homeomorphism. -/ -lemma Homeomorph.comp_isStrictMap_iff (e : Y ≃ₜ Z) {f : X → Y} : +lemma _root_.Homeomorph.comp_isStrictMap_iff (e : Y ≃ₜ Z) {f : X → Y} : IsStrictMap (e ∘ f) ↔ IsStrictMap f := e.isEmbedding.isStrictMap_iff.symm end Topology - -namespace MonoidHom - -variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] (f : G →* H) (g : G' →* H') - [TopologicalSpace G] [IsTopologicalGroup G] [TopologicalSpace H] - -/-- A group homomorphism is strict if and only if its `rangeRestrict` is an open quotient map. -/ -@[to_additive] lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict : - IsStrictMap f ↔ IsOpenQuotientMap f.rangeRestrict := by - rw [isOpenQuotientMap_iff_isQuotientMap] - rfl - -variable {f g} [TopologicalSpace G'] [IsTopologicalGroup G'] [TopologicalSpace H'] - -/-- The product (in the sense of `Prod.map`) of group homomorphisms is strict if and only if each -of the morphisms is strict. -/ -@[to_additive isStrictMap_prodMap_iff] lemma isStrictMap_prodMap_iff : - IsStrictMap (f.prodMap g) ↔ IsStrictMap f ∧ IsStrictMap g := by - simp_rw [isStrictMap_iff_isOpenQuotientMap_rangeRestrict] - let Φ : (f.prodMap g).range ≃ₜ f.range × g.range := - (Homeomorph.setCongr (by simp [Subgroup.coe_prod])).trans (Homeomorph.Set.prod _ _) - have eq : Φ ∘ (f.prodMap g).rangeRestrict = f.rangeRestrict.prodMap g.rangeRestrict := rfl - rw [← Φ.comp_isOpenQuotientMap_iff, eq, MonoidHom.coe_prodMap, isOpenQuotientMap_prodMap_iff] - -/-- The product (in the sense of `Prod.map`) of strict group homomorphisms is strict -/ -@[to_additive isStrictMap_prodMap] lemma isStrictMap_prodMap (hf : IsStrictMap f) - (hg : IsStrictMap g) : IsStrictMap (f.prodMap g) := - isStrictMap_prodMap_iff.mpr ⟨hf, hg⟩ - --- TODO Add the lemma `isStrictMap_piMap` once `MonoidHom.piMap` has been defined. - -end MonoidHom diff --git a/Mathlib/Topology/Maps/Strict/Group.lean b/Mathlib/Topology/Maps/Strict/Group.lean new file mode 100644 index 00000000000000..189efd15c9dbff --- /dev/null +++ b/Mathlib/Topology/Maps/Strict/Group.lean @@ -0,0 +1,77 @@ +/- +Copyright (c) 2026 Ziyan Wei. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Ziyan Wei, Anatole Dedecker +-/ +module + +public import Mathlib.Topology.Maps.Strict.Basic +public import Mathlib.GroupTheory.QuotientGroup.Basic +public import Mathlib.Topology.Algebra.ContinuousMonoidHom + +/-! +# Strict Group Homomorphisms + +-/ + +@[expose] public section + +open Function Set Topology QuotientGroup + +namespace MonoidHom + +variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] (f : G →* H) (g : G' →* H') + [TopologicalSpace G] [TopologicalSpace H] + +/-- A group homomorphism is strict if and only if its `rangeRestrict` is an open quotient map. -/ +@[to_additive] protected lemma isStrictMap_iff_isEmbedding_kerLift : + IsStrictMap f ↔ IsEmbedding (kerLift f) := by + -- Note: `G ⧸ MonoidHom.ker f` and `G ⧸ Setoid.ker f` are not definitionally equal, so + -- using `Topology.isStrictMap_iff_isEmbedding_kerLift` is too painful here. + simp_rw [isEmbedding_iff_isStrictMap_injective, kerLift_injective, and_true, + (isQuotientMap_mk _).isStrictMap_iff] + rfl + +/-- A group homomorphism is strict if and only if its `rangeRestrict` is an open quotient map. -/ +@[to_additive] protected lemma isStrictMap_iff_isHomeomorph_quotientKerEquivRange : + IsStrictMap f ↔ IsHomeomorph (quotientKerEquivRange f) := by + -- Note: `G ⧸ MonoidHom.ker f` and `G ⧸ Setoid.ker f` are not definitionally equal, so + -- using `Topology.isStrictMap_iff_isHomeomorph_quotientKerEquivRange` is too painful here. + simp_rw [isHomeomorph_iff_isStrictMap_bijective, EquivLike.bijective, and_true, + (isQuotientMap_mk _).isStrictMap_iff, IsEmbedding.subtypeVal.isStrictMap_iff] + rfl + +variable {f} in +noncomputable def _root_.ContinuousMulEquiv.quotientKerEquivRange (hf : IsStrictMap f) : + G ⧸ f.ker ≃ₜ* f.range where + toMulEquiv := QuotientGroup.quotientKerEquivRange f + __ := (f.isStrictMap_iff_isHomeomorph_quotientKerEquivRange.mp hf).homeomorph + +variable [IsTopologicalGroup G] + +/-- A group homomorphism is strict if and only if its `rangeRestrict` is an open quotient map. -/ +@[to_additive] protected lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict : + IsStrictMap f ↔ IsOpenQuotientMap f.rangeRestrict := by + rw [isOpenQuotientMap_iff_isQuotientMap] + rfl + +variable {f g} [TopologicalSpace G'] [IsTopologicalGroup G'] [TopologicalSpace H'] + +/-- The product (in the sense of `Prod.map`) of group homomorphisms is strict if and only if each +of the morphisms is strict. -/ +@[to_additive isStrictMap_prodMap_iff] protected lemma isStrictMap_prodMap_iff : + IsStrictMap (f.prodMap g) ↔ IsStrictMap f ∧ IsStrictMap g := by + simp_rw [MonoidHom.isStrictMap_iff_isOpenQuotientMap_rangeRestrict] + let Φ : (f.prodMap g).range ≃ₜ f.range × g.range := + (Homeomorph.setCongr (by simp [Subgroup.coe_prod])).trans (Homeomorph.Set.prod _ _) + have eq : Φ ∘ (f.prodMap g).rangeRestrict = f.rangeRestrict.prodMap g.rangeRestrict := rfl + rw [← Φ.comp_isOpenQuotientMap_iff, eq, MonoidHom.coe_prodMap, isOpenQuotientMap_prodMap_iff] + +/-- The product (in the sense of `Prod.map`) of strict group homomorphisms is strict -/ +@[to_additive isStrictMap_prodMap] protected lemma isStrictMap_prodMap (hf : IsStrictMap f) + (hg : IsStrictMap g) : IsStrictMap (f.prodMap g) := + MonoidHom.isStrictMap_prodMap_iff.mpr ⟨hf, hg⟩ + +-- TODO Add the lemma `isStrictMap_piMap` once `MonoidHom.piMap` has been defined. + +end MonoidHom From d8445eed99c44415c23d4cd32c90a7fb55e14510 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 1 Jul 2026 14:56:50 +0200 Subject: [PATCH 163/210] Done --- Mathlib/Topology/Maps/Strict/Basic.lean | 13 ------------- Mathlib/Topology/Maps/Strict/Group.lean | 26 ++++++++++++++++++++----- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index 71113fae5323f7..2bf2540a33018e 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -9,7 +9,6 @@ public import Mathlib.Topology.Maps.Basic public import Mathlib.Topology.Homeomorph.Quotient public import Mathlib.Topology.Constructions public import Mathlib.Data.Setoid.Basic -public import Mathlib.Topology.Algebra.Group.Quotient /-! # Bourbaki Strict Maps @@ -35,18 +34,6 @@ We provide several equivalent ways to characterize a strict map `f`: the canonical bijection `Quotient (Setoid.ker f) ≃ Set.range f` is a homeomorphism. * `Topology.isStrictMap_iff_isEmbedding_kerLift`: `f` is strict if and only if the canonical injection `Quotient (Setoid.ker f) → Y` (`Setoid.kerLift f`) is an embedding. - -### Group homomorphisms - -In general, the product (in the sense of `Prod.map`) of two strict maps need not be strict. -But thanks to `MonoidHom.isOpenQuotientMap_of_isQuotientMap`, we can replace `IsQuotientMap` -by `IsOpenQuotientMap` in the setting of group homomorphisms. Therefore we provide several -important properties of strict group homomorphisms : - -* `isStrictMap_iff_isOpenQuotientMap_rangeRestrict`: `f` is a strict group homomorphism if - and only if the `rangeRestrict` of `f` is an open quotient map. -* `isStrictMap_prodMap`: The product (in the sense of Prod.map) of strict group homomorphisms - is strict. -/ @[expose] public section diff --git a/Mathlib/Topology/Maps/Strict/Group.lean b/Mathlib/Topology/Maps/Strict/Group.lean index 189efd15c9dbff..31750036006c9d 100644 --- a/Mathlib/Topology/Maps/Strict/Group.lean +++ b/Mathlib/Topology/Maps/Strict/Group.lean @@ -5,13 +5,26 @@ Authors: Ziyan Wei, Anatole Dedecker -/ module -public import Mathlib.Topology.Maps.Strict.Basic public import Mathlib.GroupTheory.QuotientGroup.Basic public import Mathlib.Topology.Algebra.ContinuousMonoidHom +public import Mathlib.Topology.Algebra.Group.Quotient +public import Mathlib.Topology.Maps.Strict.Basic /-! # Strict Group Homomorphisms +In this file, we study homomorphisms of topological groups which are *strict* in the sense +of `Topology.IsStrictMap`. + +We provide specialized variations of general facts about `IsStrictMap` for convenience. +But we also show that strict group homomorphisms enjoy some extra properties compared to general +strict maps. Namely, we provide: +* `isStrictMap_iff_isOpenQuotientMap_rangeRestrict`: `f` is a strict group homomorphism if + and only if the `rangeRestrict` of `f` is an *open* quotient map. This ultimately relies + on `MonoidHom.isOpenQuotientMap_of_isQuotientMap`. +* `isStrictMap_prodMap`: The product (in the sense of `MonoidHom.prodMap`) of strict group + homomorphisms is strict. Note that this result is false for general maps; what makes things work + in our context is that, unlike `IsQuotientMap`, `IsOpenQuotientMap` is stable under product. -/ @[expose] public section @@ -23,7 +36,7 @@ namespace MonoidHom variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] (f : G →* H) (g : G' →* H') [TopologicalSpace G] [TopologicalSpace H] -/-- A group homomorphism is strict if and only if its `rangeRestrict` is an open quotient map. -/ +/-- A group homomorphism is strict if and only if its `QuotientGroup.kerLift` is an embedding. -/ @[to_additive] protected lemma isStrictMap_iff_isEmbedding_kerLift : IsStrictMap f ↔ IsEmbedding (kerLift f) := by -- Note: `G ⧸ MonoidHom.ker f` and `G ⧸ Setoid.ker f` are not definitionally equal, so @@ -32,7 +45,8 @@ variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] (f : G (isQuotientMap_mk _).isStrictMap_iff] rfl -/-- A group homomorphism is strict if and only if its `rangeRestrict` is an open quotient map. -/ +/-- A group homomorphism is strict if and only if the canonical isomorphism +`G ⧸ f.ker ≃ f.range` is a homeomorphism. -/ @[to_additive] protected lemma isStrictMap_iff_isHomeomorph_quotientKerEquivRange : IsStrictMap f ↔ IsHomeomorph (quotientKerEquivRange f) := by -- Note: `G ⧸ MonoidHom.ker f` and `G ⧸ Setoid.ker f` are not definitionally equal, so @@ -42,8 +56,10 @@ variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] (f : G rfl variable {f} in -noncomputable def _root_.ContinuousMulEquiv.quotientKerEquivRange (hf : IsStrictMap f) : - G ⧸ f.ker ≃ₜ* f.range where +/-- The isomorphism of topological groups `G ⧸ f.ker ≃ f.range` given by a strict group +homomorphism `f`. This is an avatar of the first isomorphism theorem. -/ +@[to_additive] noncomputable def _root_.ContinuousMulEquiv.quotientKerEquivRange + (hf : IsStrictMap f) : G ⧸ f.ker ≃ₜ* f.range where toMulEquiv := QuotientGroup.quotientKerEquivRange f __ := (f.isStrictMap_iff_isHomeomorph_quotientKerEquivRange.mp hf).homeomorph From 52b7d3505c67cf5fe23d995d8e883055ffc0f0e9 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 1 Jul 2026 16:41:06 +0200 Subject: [PATCH 164/210] docstrings --- Mathlib/Topology/Maps/Strict/Group.lean | 28 ++++++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/Mathlib/Topology/Maps/Strict/Group.lean b/Mathlib/Topology/Maps/Strict/Group.lean index 31750036006c9d..d8ea8634f26d66 100644 --- a/Mathlib/Topology/Maps/Strict/Group.lean +++ b/Mathlib/Topology/Maps/Strict/Group.lean @@ -37,7 +37,9 @@ variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] (f : G [TopologicalSpace G] [TopologicalSpace H] /-- A group homomorphism is strict if and only if its `QuotientGroup.kerLift` is an embedding. -/ -@[to_additive] protected lemma isStrictMap_iff_isEmbedding_kerLift : +@[to_additive /-- An additive group homomorphism is strict if and only if its +`QuotientAddGroup.kerLift` is an embedding. -/] +protected lemma isStrictMap_iff_isEmbedding_kerLift : IsStrictMap f ↔ IsEmbedding (kerLift f) := by -- Note: `G ⧸ MonoidHom.ker f` and `G ⧸ Setoid.ker f` are not definitionally equal, so -- using `Topology.isStrictMap_iff_isEmbedding_kerLift` is too painful here. @@ -47,7 +49,9 @@ variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] (f : G /-- A group homomorphism is strict if and only if the canonical isomorphism `G ⧸ f.ker ≃ f.range` is a homeomorphism. -/ -@[to_additive] protected lemma isStrictMap_iff_isHomeomorph_quotientKerEquivRange : +@[to_additive /-- An additive group homomorphism is strict if and only if the canonical isomorphism +`G ⧸ f.ker ≃ f.range` is a homeomorphism. -/] +protected lemma isStrictMap_iff_isHomeomorph_quotientKerEquivRange : IsStrictMap f ↔ IsHomeomorph (quotientKerEquivRange f) := by -- Note: `G ⧸ MonoidHom.ker f` and `G ⧸ Setoid.ker f` are not definitionally equal, so -- using `Topology.isStrictMap_iff_isHomeomorph_quotientKerEquivRange` is too painful here. @@ -58,7 +62,9 @@ variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] (f : G variable {f} in /-- The isomorphism of topological groups `G ⧸ f.ker ≃ f.range` given by a strict group homomorphism `f`. This is an avatar of the first isomorphism theorem. -/ -@[to_additive] noncomputable def _root_.ContinuousMulEquiv.quotientKerEquivRange +@[to_additive /-- The isomorphism of topological additive groups `G ⧸ f.ker ≃ f.range` given by a +strict additive group homomorphism `f`. This is an avatar of the first isomorphism theorem. -/] +noncomputable def _root_.ContinuousMulEquiv.quotientKerEquivRange (hf : IsStrictMap f) : G ⧸ f.ker ≃ₜ* f.range where toMulEquiv := QuotientGroup.quotientKerEquivRange f __ := (f.isStrictMap_iff_isHomeomorph_quotientKerEquivRange.mp hf).homeomorph @@ -66,7 +72,9 @@ homomorphism `f`. This is an avatar of the first isomorphism theorem. -/ variable [IsTopologicalGroup G] /-- A group homomorphism is strict if and only if its `rangeRestrict` is an open quotient map. -/ -@[to_additive] protected lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict : +@[to_additive /-- An additive group homomorphism is strict if and only if its `rangeRestrict` is an +open quotient map. -/] +protected lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict : IsStrictMap f ↔ IsOpenQuotientMap f.rangeRestrict := by rw [isOpenQuotientMap_iff_isQuotientMap] rfl @@ -74,8 +82,10 @@ variable [IsTopologicalGroup G] variable {f g} [TopologicalSpace G'] [IsTopologicalGroup G'] [TopologicalSpace H'] /-- The product (in the sense of `Prod.map`) of group homomorphisms is strict if and only if each -of the morphisms is strict. -/ -@[to_additive isStrictMap_prodMap_iff] protected lemma isStrictMap_prodMap_iff : +of the homomorphisms is strict. -/ +@[to_additive isStrictMap_prodMap_iff /-- The product (in the sense of `Prod.map`) of additive group +homomorphisms is strict if and only if each of the homomorphisms is strict. -/] +protected lemma isStrictMap_prodMap_iff : IsStrictMap (f.prodMap g) ↔ IsStrictMap f ∧ IsStrictMap g := by simp_rw [MonoidHom.isStrictMap_iff_isOpenQuotientMap_rangeRestrict] let Φ : (f.prodMap g).range ≃ₜ f.range × g.range := @@ -83,8 +93,10 @@ of the morphisms is strict. -/ have eq : Φ ∘ (f.prodMap g).rangeRestrict = f.rangeRestrict.prodMap g.rangeRestrict := rfl rw [← Φ.comp_isOpenQuotientMap_iff, eq, MonoidHom.coe_prodMap, isOpenQuotientMap_prodMap_iff] -/-- The product (in the sense of `Prod.map`) of strict group homomorphisms is strict -/ -@[to_additive isStrictMap_prodMap] protected lemma isStrictMap_prodMap (hf : IsStrictMap f) +/-- The product (in the sense of `Prod.map`) of strict group homomorphisms is strict. -/ +@[to_additive isStrictMap_prodMap /-- The product (in the sense of `Prod.map`) of strict additive +group homomorphisms is strict. -/] +protected lemma isStrictMap_prodMap (hf : IsStrictMap f) (hg : IsStrictMap g) : IsStrictMap (f.prodMap g) := MonoidHom.isStrictMap_prodMap_iff.mpr ⟨hf, hg⟩ From afab0d833ceed7fda3910069755287ccffbe797d Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 1 Jul 2026 17:26:15 +0200 Subject: [PATCH 165/210] add Subtype.coind_injective_iff --- Mathlib/Data/Subtype.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Mathlib/Data/Subtype.lean b/Mathlib/Data/Subtype.lean index 84c50fde8f3a6a..abce50412ff816 100644 --- a/Mathlib/Data/Subtype.lean +++ b/Mathlib/Data/Subtype.lean @@ -135,6 +135,10 @@ def coind {α β} (f : α → β) {p : β → Prop} (h : ∀ a, p (f a)) : α theorem coind_injective {α β} {f : α → β} {p : β → Prop} (h : ∀ a, p (f a)) (hf : Injective f) : Injective (coind f h) := fun x y hxy ↦ hf <| by apply congr_arg Subtype.val hxy +@[simp] theorem coind_injective_iff {α β} {f : α → β} {p : β → Prop} (h : ∀ a, p (f a)) : + Injective (coind f h) ↔ Injective f := + ⟨Subtype.coe_injective.comp, coind_injective h⟩ + /-- Restriction of a function to a function on subtypes. -/ @[simps] def map {p : α → Prop} {q : β → Prop} (f : α → β) (h : ∀ a, p a → q (f a)) : From 2e3a9066f8a5b13ed0a954c93f4ee867834fb4a9 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 1 Jul 2026 18:25:18 +0200 Subject: [PATCH 166/210] feat: convenience API for strict linear maps --- Mathlib.lean | 1 + Mathlib/Topology/Maps/Strict/Module.lean | 75 ++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 Mathlib/Topology/Maps/Strict/Module.lean diff --git a/Mathlib.lean b/Mathlib.lean index 907d5cff55352b..dafaa2dc2fca3e 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -7952,6 +7952,7 @@ public import Mathlib.Topology.Maps.Proper.CompactlyGenerated public import Mathlib.Topology.Maps.Proper.UniversallyClosed public import Mathlib.Topology.Maps.Strict.Basic public import Mathlib.Topology.Maps.Strict.Group +public import Mathlib.Topology.Maps.Strict.Module public import Mathlib.Topology.MetricSpace.Algebra public import Mathlib.Topology.MetricSpace.Antilipschitz public import Mathlib.Topology.MetricSpace.Basic diff --git a/Mathlib/Topology/Maps/Strict/Module.lean b/Mathlib/Topology/Maps/Strict/Module.lean new file mode 100644 index 00000000000000..17d4dc8eda186a --- /dev/null +++ b/Mathlib/Topology/Maps/Strict/Module.lean @@ -0,0 +1,75 @@ +/- +Copyright (c) 2026 Anatole Dedecker. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Anatole Dedecker +-/ +module + +public import Mathlib.LinearAlgebra.Isomorphisms +public import Mathlib.Topology.Algebra.Module.ContinuousLinearMap.Quotient +public import Mathlib.Topology.Algebra.Module.Equiv +public import Mathlib.Topology.Maps.Strict.Group + +/-! +# Strict Group Homomorphisms + +In this file, we study continuous linear maps which are *strict* in the sense of +`Topology.IsStrictMap`. So far, all the results in this file are direct +adaptations from the theory of strict homomorphisms of topological additive groups, +but this may change in the future. +-/ + + +@[expose] public section + +open Function Set Topology QuotientGroup + +namespace LinearMap + +variable {R S M N Nₗ M' Nₗ' : Type*} [Ring R] [Ring S] {σ : R →+* S} + [AddCommGroup M] [AddCommGroup N] [AddCommGroup Nₗ] [AddCommGroup M'] [AddCommGroup Nₗ'] + [Module R M] [Module S N] [Module R Nₗ] [Module R M'] [Module R Nₗ'] + (f : M →ₛₗ[σ] N) (fₗ : M →ₗ[R] Nₗ) (gₗ : M' →ₗ[R] Nₗ') + [TopologicalSpace M] [TopologicalSpace N] [TopologicalSpace Nₗ] + +/-- A group homomorphism is strict if and only if its `QuotientGroup.kerLift` is an embedding. -/ +protected lemma isStrictMap_iff_isEmbedding_liftQ_ker : + IsStrictMap f ↔ IsEmbedding (f.ker.liftQ f le_rfl) := + f.toAddMonoidHom.isStrictMap_iff_isEmbedding_kerLift + +/-- A group homomorphism is strict if and only if the canonical isomorphism +`G ⧸ f.ker ≃ f.range` is a homeomorphism. -/ +protected lemma isStrictMap_iff_isHomeomorph_quotKerEquivRange : + IsStrictMap fₗ ↔ IsHomeomorph (fₗ.quotKerEquivRange) := by + simp_rw [isHomeomorph_iff_isStrictMap_bijective, EquivLike.bijective, and_true, + fₗ.ker.isQuotientMap_mkQ.isStrictMap_iff, IsEmbedding.subtypeVal.isStrictMap_iff] + rfl + +variable {f} in +/-- The isomorphism of topological groups `G ⧸ f.ker ≃ f.range` given by a strict group +homomorphism `f`. This is an avatar of the first isomorphism theorem. -/ +noncomputable def _root_.ContinuousLinearEquiv.quotKerEquivRange + (hf : IsStrictMap fₗ) : (M ⧸ fₗ.ker) ≃L[R] fₗ.range := + .ofIsHomeomorph fₗ.quotKerEquivRange (fₗ.isStrictMap_iff_isHomeomorph_quotKerEquivRange.mp hf) + +variable [IsTopologicalAddGroup M] + +/-- A group homomorphism is strict if and only if its `rangeRestrict` is an open quotient map. -/ +protected lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict [RingHomSurjective σ] : + IsStrictMap f ↔ IsOpenQuotientMap f.rangeRestrict := + f.toAddMonoidHom.isStrictMap_iff_isOpenQuotientMap_rangeRestrict + +variable {f fₗ gₗ} [TopologicalSpace M'] [IsTopologicalAddGroup M'] [TopologicalSpace Nₗ'] + +/-- The product (in the sense of `Prod.map`) of group homomorphisms is strict if and only if each +of the homomorphisms is strict. -/ +protected lemma isStrictMap_prodMap_iff : + IsStrictMap (fₗ.prodMap gₗ) ↔ IsStrictMap fₗ ∧ IsStrictMap gₗ := + AddMonoidHom.isStrictMap_prodMap_iff (f := fₗ.toAddMonoidHom) (g := gₗ.toAddMonoidHom) + +/-- The product (in the sense of `Prod.map`) of strict group homomorphisms is strict. -/ +protected lemma isStrictMap_prodMap (hf : IsStrictMap fₗ) + (hg : IsStrictMap gₗ) : IsStrictMap (fₗ.prodMap gₗ) := + LinearMap.isStrictMap_prodMap_iff.mpr ⟨hf, hg⟩ + +end LinearMap From 7af7121b417fc2bcbf7792bfdf620d2ede89d203 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 1 Jul 2026 22:30:59 +0200 Subject: [PATCH 167/210] golf using first iso theorem for strict maps --- Mathlib/Analysis/FredholmOperator.lean | 33 +++++-------------- .../Operator/Perturbation/StrictByFinite.lean | 8 ++--- 2 files changed, 12 insertions(+), 29 deletions(-) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index e36aae9737e9ba..4bb4d6082c2936 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -170,28 +170,6 @@ def IsFredholm.fredholmDecomposition {u : E →L[𝕜] F} (u_fred : IsFredholm u) {dom₁ : Submodule 𝕜 E} {codom₀ : Submodule 𝕜 F} (h_dom : IsTopCompl u.ker dom₁) (h_codom : IsTopCompl codom₀ u.range) : FredholmDecomposition u := - haveI u_mapsto : MapsTo u dom₁ u.range := Set.mapsTo_range _ _ - haveI uₗ_mapsto : MapsTo u.toLinearMap dom₁ u.range := u_mapsto - haveI u_eq_u_restr : u = u.range.subtypeL ∘L u.restrict u_mapsto ∘L - dom₁.projectionOntoL u.ker h_dom.symm := by - refine LinearMap.ext_on_codisjoint h_dom.isCompl.codisjoint ?_ ?_ - · intro x (hx : u x = 0) - simp [hx, projection_apply_of_mem_right] - · intro x (hx : x ∈ dom₁) - simp [hx, projection_apply_of_mem_left] - haveI u_restr_isHomeo : IsHomeomorph (u.restrict u_mapsto) := by - -- This is a bit messy - rw [isHomeomorph_iff_isStrictMap_bijective] - constructor - · rw [u.range.isEmbedding_subtypeL.isStrictMap_iff, ← coe_comp, - (isQuotientMap_projectionOntoL h_dom.symm).isStrictMap_iff, ← coe_comp, - comp_assoc, ← u_eq_u_restr] - exact u_fred.isStrictMap - · constructor - · simpa [← coe_coe, injective_restrict_iff_disjoint] using h_dom.isCompl.symm.disjoint - · suffices u.range ≤ map u.toLinearMap dom₁ by simpa [← coe_coe, ← LinearMap.range_eq_top] - simpa [← Submodule.map_top, Submodule.map_le_iff_le_comap, Submodule.comap_map_eq] - using h_dom.isCompl.symm.sup_eq_top { dom₀ := u.ker dom₁ := dom₁ finite_dom₀ := u_fred.finite_ker @@ -201,8 +179,15 @@ def IsFredholm.fredholmDecomposition {u : E →L[𝕜] F} finite_codom₀ := Module.Finite.of_fg <| u_fred.finite_coker.fg_of_isCompl h_codom.isCompl.symm isTopCompl_codom := h_codom equiv := - .ofIsHomeomorph (.ofBijective _ u_restr_isHomeo.bijective) u_restr_isHomeo - eq_equiv' := u_eq_u_restr } + letI Φ : dom₁ ≃L[𝕜] E ⧸ u.ker := u.ker.quotientEquivOfIsTopCompl dom₁ h_dom |>.symm + letI Ψ : (E ⧸ u.ker) ≃L[𝕜] u.range := .quotKerEquivRange u.toLinearMap u_fred.isStrictMap + Φ.trans Ψ + eq_equiv' := by + refine LinearMap.ext_on_codisjoint h_dom.isCompl.codisjoint ?_ ?_ + · intro x (hx : u x = 0) + simp [hx, projection_apply_of_mem_right] + · intro x (hx : x ∈ dom₁) + simp [hx, projection_apply_of_mem_left, ContinuousLinearEquiv.quotKerEquivRange] } omit [ContinuousSMul 𝕜 E] in theorem IsFredholm.nonempty_fredholmDecomposition {u : E →L[𝕜] F} diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 9cd52a58ced298..956af7dd468909 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -6,7 +6,7 @@ Authors: Anatole Dedecker module public import Mathlib.RingTheory.Finiteness.Cofinite -public import Mathlib.Topology.Maps.Strict.Basic +public import Mathlib.Topology.Maps.Strict.Module public import Mathlib.Topology.LocalAtTarget public import Mathlib.Topology.Algebra.Module.FiniteDimension public import Mathlib.Algebra.Module.LinearMap.FiniteRange @@ -121,10 +121,8 @@ theorem step1 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) rwa [u_restr_eq, u_eq, ← (isEmbedding_subtypeL _).isStrictMap_iff, ← Ψ.isHomeomorph.isEmbedding.isStrictMap_iff, ← Φ.symm.isHomeomorph.isQuotientMap.isStrictMap_iff] - -- TODO: we should think of a way to avoid this - change IsStrictMap (uₛ.toAddMonoidHom.prodMap uₐ.toAddMonoidHom) ↔ IsStrictMap uₐ - simp_rw [AddMonoidHom.isStrictMap_prodMap_iff, LinearMap.toAddMonoidHom_coe, coe_coe, - uₛ.isStrictMap_of_finiteDimensional, true_and] + simp_rw [← coe_coe, ContinuousLinearMap.coe_prodMap, LinearMap.isStrictMap_prodMap_iff, + coe_coe, uₛ.isStrictMap_of_finiteDimensional, true_and] /-! ### Step 2 From e03425f935320fa24463c1834451a4df024383b2 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 1 Jul 2026 22:49:53 +0200 Subject: [PATCH 168/210] Compare with Bourbaki --- .../Operator/Perturbation/StrictByFinite.lean | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 9cd52a58ced298..0efaa433a6f780 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -34,9 +34,24 @@ These three results show up crucially when developping the theory of Fredholm op between topological vector spaces. Note that none of the results here use the Hahn-Banach theorem, so there is no significant restriction on the field. +## Implementation details + +There are two notable changes compared to Bourbaki. +* We treat all topological vector spaces over complete nontrivially normed fields, + where Bourbaki restricts to locally convex spaces over `ℝ` or `ℂ`. To do so, we have to + tweak one statement by assuming that a finite dimensional subspace is complemented, which + is always the case when you have Hahn-Banach available. +* We give a different proof, where we reduce the statement to + `AddMonoidHom.isStrictMap_prodMap_iff`. This gives a slightly longer proof, but we + claim that it is more natural. + +Note that these two changes are independent: the extra generality could have been achieved +with Bourbaki's proof. + ## References * [N. Bourbaki, *Théories Spectrales*, Chapitre III, § 3, n° 1][bourbaki2023] + -/ open Topology Set Submodule Function ContinuousLinearMap From 923957a64485752f5b574588bdf409d66f98eb6d Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Wed, 1 Jul 2026 22:59:05 +0200 Subject: [PATCH 169/210] Update Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean --- .../Analysis/Normed/Operator/Perturbation/StrictByFinite.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 0efaa433a6f780..95e80225f45711 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -273,7 +273,7 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Sp have strict_iff : IsStrictMap u ↔ IsStrictMap v := by rw [← v_comp_π_eq_u, coe_comp, ← π_quot.isQuotientMap.isStrictMap_iff] -- Now, recall the equality `A = comap π B`; it ensures that the restriction - -- `π' : A → B` of the open quotient map `π` is *still* an (open quotient map). + -- `π' : A → B` of the open quotient map `π` is *still* an (open) quotient map. set π' : A →L[𝕜] B := π.restrict A_mapsTo_B have π'_quot : IsOpenQuotientMap π' := by let φ : (N.mkQL ⁻¹' B) ≃ₜ A := .setCongr congr(SetLike.coe $comap_B) From c8587a6b9ad389f81613334ae6d77b1c1df4dd1e Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Wed, 1 Jul 2026 23:00:35 +0200 Subject: [PATCH 170/210] Update Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean --- .../Analysis/Normed/Operator/Perturbation/StrictByFinite.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 95e80225f45711..f69ad988b24ef3 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -310,7 +310,7 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_eqOn [T2Spa open LinearMap.FiniteRangeSetoid -/-- If `u, v : E →L[𝕜] F` differ by a finite rank continuous linear map (recall that this is +/-- If `u, v : E →L[𝕜] F` differ by a finite rank linear map (recall that this is denoted `u.toLinearMap ≈ v.toLinearMap` in scope `LinearMap.FiniteRangeSetoid`), then `u` is strict with closed range if and only if `v` is strict with closed range. From 40909509ff1b76170bce6a8bca97632b4c2aaee0 Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Wed, 1 Jul 2026 23:01:45 +0200 Subject: [PATCH 171/210] Update Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean --- .../Analysis/Normed/Operator/Perturbation/StrictByFinite.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index f69ad988b24ef3..afb0cdf2201037 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -330,7 +330,7 @@ section FiniteDimQuotient open LinearMap.FiniteRangeSetoid -/-- Consider `u : E →L[𝕜] F` and `B` a *complemented* finite dimensional subspace `F`. We have +/-- Consider `u : E →L[𝕜] F` and `B` a *complemented* finite dimensional subspace of `F`. We have that `u` is strict with closed range if and only if `B.mkQL ∘L u` is strict with closed range. This is [N. Bourbaki, *Théories Spectrales*, Chapitre III, § 3, n° 1, Cor. 2][bourbaki2023]. -/ From f376f78aa560b9b88547688fdfa5639129d4d869 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 1 Jul 2026 23:21:35 +0200 Subject: [PATCH 172/210] fix docstrings --- Mathlib/Topology/Maps/Strict/Module.lean | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Mathlib/Topology/Maps/Strict/Module.lean b/Mathlib/Topology/Maps/Strict/Module.lean index 17d4dc8eda186a..ebce43ec67c655 100644 --- a/Mathlib/Topology/Maps/Strict/Module.lean +++ b/Mathlib/Topology/Maps/Strict/Module.lean @@ -32,13 +32,14 @@ variable {R S M N Nₗ M' Nₗ' : Type*} [Ring R] [Ring S] {σ : R →+* S} (f : M →ₛₗ[σ] N) (fₗ : M →ₗ[R] Nₗ) (gₗ : M' →ₗ[R] Nₗ') [TopologicalSpace M] [TopologicalSpace N] [TopologicalSpace Nₗ] -/-- A group homomorphism is strict if and only if its `QuotientGroup.kerLift` is an embedding. -/ +/-- A linear map `f : E → F` is strict if and only the induced map `E ⧸ f.ker → F` is an +embedding. -/ protected lemma isStrictMap_iff_isEmbedding_liftQ_ker : IsStrictMap f ↔ IsEmbedding (f.ker.liftQ f le_rfl) := f.toAddMonoidHom.isStrictMap_iff_isEmbedding_kerLift -/-- A group homomorphism is strict if and only if the canonical isomorphism -`G ⧸ f.ker ≃ f.range` is a homeomorphism. -/ +/-- A linear map `f : E → F` is strict if and only if the canonical isomorphism +`E ⧸ f.ker ≃ f.range` is a homeomorphism. -/ protected lemma isStrictMap_iff_isHomeomorph_quotKerEquivRange : IsStrictMap fₗ ↔ IsHomeomorph (fₗ.quotKerEquivRange) := by simp_rw [isHomeomorph_iff_isStrictMap_bijective, EquivLike.bijective, and_true, @@ -46,28 +47,28 @@ protected lemma isStrictMap_iff_isHomeomorph_quotKerEquivRange : rfl variable {f} in -/-- The isomorphism of topological groups `G ⧸ f.ker ≃ f.range` given by a strict group -homomorphism `f`. This is an avatar of the first isomorphism theorem. -/ +/-- The isomorphism of topological modules `E ⧸ f.ker ≃ f.range` given by a strict linear +map `f : E → F`. This is an avatar of the first isomorphism theorem. -/ noncomputable def _root_.ContinuousLinearEquiv.quotKerEquivRange (hf : IsStrictMap fₗ) : (M ⧸ fₗ.ker) ≃L[R] fₗ.range := .ofIsHomeomorph fₗ.quotKerEquivRange (fₗ.isStrictMap_iff_isHomeomorph_quotKerEquivRange.mp hf) variable [IsTopologicalAddGroup M] -/-- A group homomorphism is strict if and only if its `rangeRestrict` is an open quotient map. -/ +/-- A linear map is strict if and only if its `rangeRestrict` is an open quotient map. -/ protected lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict [RingHomSurjective σ] : IsStrictMap f ↔ IsOpenQuotientMap f.rangeRestrict := f.toAddMonoidHom.isStrictMap_iff_isOpenQuotientMap_rangeRestrict variable {f fₗ gₗ} [TopologicalSpace M'] [IsTopologicalAddGroup M'] [TopologicalSpace Nₗ'] -/-- The product (in the sense of `Prod.map`) of group homomorphisms is strict if and only if each -of the homomorphisms is strict. -/ +/-- The product (in the sense of `LinearMap.prodMap`) of linear maps is strict if and only if each +of the maps is strict. -/ protected lemma isStrictMap_prodMap_iff : IsStrictMap (fₗ.prodMap gₗ) ↔ IsStrictMap fₗ ∧ IsStrictMap gₗ := AddMonoidHom.isStrictMap_prodMap_iff (f := fₗ.toAddMonoidHom) (g := gₗ.toAddMonoidHom) -/-- The product (in the sense of `Prod.map`) of strict group homomorphisms is strict. -/ +/-- The product (in the sense of `LinearMap.prodMap`) of strict linear maps is strict. -/ protected lemma isStrictMap_prodMap (hf : IsStrictMap fₗ) (hg : IsStrictMap gₗ) : IsStrictMap (fₗ.prodMap gₗ) := LinearMap.isStrictMap_prodMap_iff.mpr ⟨hf, hg⟩ From 98dda6aa736ae894678c8ed6beb18d4266517151 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 2 Jul 2026 15:21:32 +0200 Subject: [PATCH 173/210] remove useless have --- .../Analysis/Normed/Operator/Perturbation/StrictByFinite.lean | 2 -- 1 file changed, 2 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index afb0cdf2201037..fe7bf133a8c131 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -250,8 +250,6 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Sp have v_ker : Disjoint v.ker B := by simp [disjoint_iff, v, B, toLinearMap_liftQL, ker_liftQ, map_inf_eq_map_inf_comap, comap_map_mkQ, N, inf_comm] - have v_restr_inj : Injective (Set.restrict B v) := - injOn_iff_injective.mp <| LinearMap.injOn_of_disjoint_ker subset_rfl v_ker.symm -- Because `A` contains `N`, we have `A = comap π B`. In particular, `B` is closed. have comap_B : comap π.toLinearMap B = A := by simp [B, N, π] have A_mapsTo_B : MapsTo π A B := fun _ ↦ by simp [← comap_B] From a133dd8a7571b4e5fccfd4b15a12a30c29b7073a Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Thu, 2 Jul 2026 23:52:21 +0200 Subject: [PATCH 174/210] Update StrictByFinite.lean Co-authored-by: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> --- .../Analysis/Normed/Operator/Perturbation/StrictByFinite.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index fe7bf133a8c131..806ed493a3a857 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -23,7 +23,7 @@ More precisely, we prove the following statements: * `ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict`: given a closed subspace `A` of `E` of finite codimension, we have that `u` is strict with closed range if and only if `u.domRestrict A` is strict with closed range. -* `ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict`: if `u, v : E →L[𝕜] F` +* `ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_finiteRangeSetoid`: if `u, v : E →L[𝕜] F` differ by a finite rank continuous linear map, then `u` is strict with closed range if and only if `v` is strict with closed range. * `ContinuousLinearMap.isStrictMap_isClosed_range_iff_quotient`: given a *complemented* From dd40d80d3d615bcb2c39c04fa8197b4683fd5027 Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Thu, 2 Jul 2026 23:53:35 +0200 Subject: [PATCH 175/210] Update StrictByFinite.lean Co-authored-by: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> --- .../Analysis/Normed/Operator/Perturbation/StrictByFinite.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 806ed493a3a857..2af1c9548703b0 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -56,7 +56,7 @@ with Bourbaki's proof. open Topology Set Submodule Function ContinuousLinearMap -variable {𝕜} +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] [CompleteSpace 𝕜] variable {E F : Type*} From bc99a62c26156f5f5bdca2f186e1ba74a5f33f5b Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Thu, 2 Jul 2026 23:55:50 +0200 Subject: [PATCH 176/210] Update StrictByFinite.lean Co-authored-by: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> --- .../Analysis/Normed/Operator/Perturbation/StrictByFinite.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 2af1c9548703b0..6cc7d9a5a07abe 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -115,7 +115,7 @@ theorem step1 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) replace S_compl_A : IsTopCompl S A := S_compl_A.symm.isTopCompl_of_finiteDimensional_quotient A_closed |>.symm replace uS_compl_uA : IsTopCompl (map u.toLinearMap S) (map u.toLinearMap A) := - uS_compl_uA.symm.isTopCompl_of_isClosed_of_finiteDimensional uA_closed |>.symm + uS_compl_uA.symm.isTopCompl_of_isClosed_of_finiteDimensional uA_closed |>.symm -- Thus, we have decomposed both the domain and the codomain into topopological complements, -- and `u` preserves this decomposition, inducing maps `uₛ : S → map u S` and `uₐ : A → map u A`. set uₛ : S →L[𝕜] map u.toLinearMap S := u.restrict (fun _ ↦ mem_map_of_mem) From 67487288fe485c05e9ce57f3f701da28c7b84d81 Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Fri, 3 Jul 2026 23:20:47 +0200 Subject: [PATCH 177/210] Update StrictByFinite.lean Co-authored-by: Ruben Van de Velde <65514131+Ruben-VandeVelde@users.noreply.github.com> --- .../Analysis/Normed/Operator/Perturbation/StrictByFinite.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 6cc7d9a5a07abe..79c19548cc1859 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -30,7 +30,7 @@ More precisely, we prove the following statements: finite dimensional subspace `B` of `F`, we have that `u` is strict with closed range if and only if `B.mkQL ∘L u` is strict with closed range. -These three results show up crucially when developping the theory of Fredholm operators +These three results show up crucially when developing the theory of Fredholm operators between topological vector spaces. Note that none of the results here use the Hahn-Banach theorem, so there is no significant restriction on the field. From 1ee23d0ea17a0cb1a5c5cd3c785d2d6e7fb0e19a Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 8 Jul 2026 20:01:30 +0200 Subject: [PATCH 178/210] feat: variations of Submodule.disjoint_map with weaker hypotheses --- Mathlib/Algebra/Module/Submodule/Map.lean | 3 +-- Mathlib/LinearAlgebra/Span/Basic.lean | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Mathlib/Algebra/Module/Submodule/Map.lean b/Mathlib/Algebra/Module/Submodule/Map.lean index 2e2f7d8ae98dc0..8ee3ab95cc8422 100644 --- a/Mathlib/Algebra/Module/Submodule/Map.lean +++ b/Mathlib/Algebra/Module/Submodule/Map.lean @@ -452,8 +452,7 @@ end OrderIso --TODO(Mario): is there a way to prove this from order properties? theorem map_inf_eq_map_inf_comap [RingHomSurjective σ₁₂] {f : M →ₛₗ[σ₁₂] M₂} {p : Submodule R M} {p' : Submodule R₂ M₂} : map f p ⊓ p' = map f (p ⊓ comap f p') := - le_antisymm (by rintro _ ⟨⟨x, h₁, rfl⟩, h₂⟩; exact ⟨_, ⟨h₁, h₂⟩, rfl⟩) - (le_inf (map_mono inf_le_left) (map_le_iff_le_comap.2 inf_le_right)) + .symm <| SetLike.coe_injective <| image_inter_preimage _ _ _ @[simp] theorem map_comap_subtype : map p.subtype (comap p.subtype p') = p ⊓ p' := diff --git a/Mathlib/LinearAlgebra/Span/Basic.lean b/Mathlib/LinearAlgebra/Span/Basic.lean index 2f16a8eb65657b..20d67960899b9e 100644 --- a/Mathlib/LinearAlgebra/Span/Basic.lean +++ b/Mathlib/LinearAlgebra/Span/Basic.lean @@ -561,6 +561,16 @@ theorem comap_map_sup_of_comap_le {f : M →ₛₗ[τ₁₂] M₂} {p : Submodul rw [add_comm, ← eq_sub_iff_add_eq, ← map_sub] at eq; subst eq simpa using p.add_mem (le hz) hy +lemma disjoint_map_of_ker_le_right {f : M →ₛₗ[τ₁₂] M₂} {p q : Submodule R M} + (hpq : Disjoint p q) (hker : f.ker ≤ q) : Disjoint (p.map f) (q.map f) := by + rw [disjoint_iff, map_inf_eq_map_inf_comap, comap_map_eq, eq_bot_iff, map_le_iff_le_comap, + comap_bot, sup_eq_left.mpr hker, hpq.eq_bot] + exact bot_le + +lemma disjoint_map_of_ker_le_left {f : M →ₛₗ[τ₁₂] M₂} {p q : Submodule R M} + (hpq : Disjoint p q) (hker : f.ker ≤ p) : Disjoint (p.map f) (q.map f) := + disjoint_map_of_ker_le_right hpq.symm hker |>.symm + theorem isCoatom_comap_or_eq_top (f : M →ₛₗ[τ₁₂] M₂) {p : Submodule R₂ M₂} (hp : IsCoatom p) : IsCoatom (comap f p) ∨ comap f p = ⊤ := or_iff_not_imp_right.mpr fun h ↦ ⟨h, fun q lt ↦ by @@ -633,6 +643,17 @@ variable [AddCommGroup M] [Module R M] [AddCommGroup M₂] [Module R₂ M₂] variable {τ₁₂ : R →+* R₂} [RingHomSurjective τ₁₂] variable {p p' : Submodule R M} +lemma disjoint_map_of_ker_le_inf_sup {f : M →ₛₗ[τ₁₂] M₂} {p q : Submodule R M} + (hpq : Disjoint p q) (hker : f.ker ≤ (f.ker ⊓ p) ⊔ (f.ker ⊓ q)) : + Disjoint (p.map f) (q.map f) := by + replace hker : f.ker = (f.ker ⊓ p) ⊔ (f.ker ⊓ q) := + le_antisymm hker (sup_le inf_le_left inf_le_left) + have : q ⊔ f.ker = q ⊔ (p ⊓ f.ker) := by + conv_lhs => rw [hker, inf_comm]; simp only [← sup_assoc, inf_left_le_sup_right, sup_of_le_left] + rw [disjoint_iff, map_inf_eq_map_inf_comap, comap_map_eq, eq_bot_iff, map_le_iff_le_comap, + comap_bot, this, ← inf_sup_assoc_of_le _ inf_le_left, hpq.eq_bot, bot_sup_eq] + exact inf_le_right + theorem map_strict_mono_or_ker_sup_lt_ker_sup (f : M →ₛₗ[τ₁₂] M₂) (hab : p < p') : Submodule.map f p < Submodule.map f p' ∨ LinearMap.ker f ⊓ p < LinearMap.ker f ⊓ p' := by obtain (⟨h, -⟩ | ⟨-, h⟩) := Prod.mk_lt_mk.mp <| strictMono_inf_prod_sup (z := LinearMap.ker f) hab From fc047ad0fa85487803b144f97bf354808dcdd208 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Wed, 8 Jul 2026 20:04:19 +0200 Subject: [PATCH 179/210] docstring --- Mathlib/LinearAlgebra/Span/Basic.lean | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Mathlib/LinearAlgebra/Span/Basic.lean b/Mathlib/LinearAlgebra/Span/Basic.lean index 20d67960899b9e..b2319a5241708c 100644 --- a/Mathlib/LinearAlgebra/Span/Basic.lean +++ b/Mathlib/LinearAlgebra/Span/Basic.lean @@ -643,6 +643,9 @@ variable [AddCommGroup M] [Module R M] [AddCommGroup M₂] [Module R₂ M₂] variable {τ₁₂ : R →+* R₂} [RingHomSurjective τ₁₂] variable {p p' : Submodule R M} +/-- Let `f : M →ₗ N`. Assume that `p` and `q` are disjoint submodules of `M`, +and that the kernel of `f` "decomposes well" wrt. `p` and `q`, in the sense that +`f.ker = (f.ker ⊓ p) ⊔ (f.ker ⊓ q)`. Then `map f p` and `map f q` are disjoint. -/ lemma disjoint_map_of_ker_le_inf_sup {f : M →ₛₗ[τ₁₂] M₂} {p q : Submodule R M} (hpq : Disjoint p q) (hker : f.ker ≤ (f.ker ⊓ p) ⊔ (f.ker ⊓ q)) : Disjoint (p.map f) (q.map f) := by From ede4204c0c2b28fb7d1d175cf8594e54459e31a7 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 9 Jul 2026 20:01:41 +0200 Subject: [PATCH 180/210] use new disjointness lemma --- .../Normed/Operator/Perturbation/StrictByFinite.lean | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 79c19548cc1859..b2a4314c3eaf81 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -104,12 +104,9 @@ theorem step1 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) -- Furthermore, because the kernel of `u` is fully contained in `S`, we can show that -- `map u S ⊓ map u A = ⊥`, so that `map u S` and `map u A` are in fact algebraic complements -- of each other. - have uS_compl_uA : IsCompl (map u.toLinearMap S) (map u.toLinearMap A) := by - constructor - · rw [disjoint_iff, inf_comm, map_inf_eq_map_inf_comap, comap_map_eq, sup_eq_left.mpr ker_le_S, - S_compl_A.symm.inf_eq_bot, Submodule.map_bot] - · rw [codisjoint_iff, ← Submodule.map_sup, S_compl_A.sup_eq_top, Submodule.map_top, - h_range] + have uS_compl_uA : IsCompl (map u.toLinearMap S) (map u.toLinearMap A) := + ⟨disjoint_map_of_ker_le_left S_compl_A.disjoint ker_le_S, + codisjoint_map (LinearMap.range_eq_top.mp h_range) S_compl_A.codisjoint⟩ -- Because `A` (resp. `map u A`) is closed and `S` (resp `map u S`) has finite dimension, -- `A` and `S` (resp `map u A` and `map u S`) are in fact *topological* complements of each other. replace S_compl_A : IsTopCompl S A := From 9761f9935fee8c38ec8b034a7845cb0914ed1094 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 9 Jul 2026 20:10:39 +0200 Subject: [PATCH 181/210] better proof for "complement has finite dimension" --- .../Operator/Perturbation/StrictByFinite.lean | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index b2a4314c3eaf81..22a9cfb6ca7daf 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -92,14 +92,13 @@ The result then follows from `AddMonoidHom.isStrictMap_prodMap_iff` and -/ theorem step1 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) - (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] + (A_closed : IsClosed (A : Set E)) [A_cofg : A.CoFG] (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) (uA_closed : IsClosed (map u.toLinearMap A : Set F)) : IsStrictMap u ↔ IsStrictMap (u.domRestrict A) := by -- Fix `S` an algebraic complement of `A` containing `u.ker`. It has finite dimension. rcases h_ker.exists_isCompl with ⟨S, ker_le_S, S_compl_A⟩ - have : FiniteDimensional 𝕜 S := - quotientEquivOfIsCompl A S S_compl_A.symm |>.finiteDimensional + have : FiniteDimensional 𝕜 S := .of_fg <| A_cofg.fg_of_isCompl S_compl_A.symm -- Because `u` is assumed surjective and `S ⊔ A = ⊤`, we have `map u S ⊔ map u A = ⊤`. -- Furthermore, because the kernel of `u` is fully contained in `S`, we can show that -- `map u S ⊓ map u A = ⊥`, so that `map u S` and `map u A` are in fact algebraic complements @@ -147,7 +146,7 @@ We prove the theorem under the assumptions that -/ theorem step2 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) - (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] + (A_closed : IsClosed (A : Set E)) [A_cofg : A.CoFG] (h_ker : Disjoint u.ker A) (h_range : u.range = ⊤) : IsStrictMap u ↔ IsStrictMap (u.domRestrict A) ∧ IsClosed (map u.toLinearMap A : Set F) := by -- To reduce to step 1, it suffices to show that `IsStrictMap u → IsClosed (map u A)`. @@ -171,7 +170,7 @@ We prove the theorem under the assumptions that -/ theorem step3 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) - (A_closed : IsClosed (A : Set E)) [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] + (A_closed : IsClosed (A : Set E)) [A_cofg : A.CoFG] (h_ker : Disjoint u.ker A) (h_range : IsClosed (u.range : Set F)) : IsStrictMap u ↔ IsStrictMap (u.domRestrict A) ∧ IsClosed (map u.toLinearMap A : Set F) := by -- Let `F' := u.range` and `i : F' →L[𝕜] F` be the inclusion map. By assumption, @@ -199,7 +198,7 @@ We prove the theorem under the assumption that `u.ker` is disjoint from `A` -/ theorem step4 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) - [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_ker : Disjoint u.ker A) : + [A_cofg : A.CoFG] (h_ker : Disjoint u.ker A) : (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ IsStrictMap (u.domRestrict A) ∧ IsClosed (map u.toLinearMap A : Set F) := by -- To reduce to step 3, it suffices to show that, if `map u A` is closed, then so is `u.range`. @@ -209,8 +208,7 @@ theorem step4 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed intro uA_closed -- Fix `S` an algebraic complement of `A` containing `u.ker`. It has finite dimension. rcases h_ker.exists_isCompl with ⟨S, ker_le_S, S_compl_A⟩ - have : FiniteDimensional 𝕜 S := - quotientEquivOfIsCompl A S S_compl_A.symm |>.finiteDimensional + have : FiniteDimensional 𝕜 S := .of_fg <| A_cofg.fg_of_isCompl S_compl_A.symm -- It follows that `u.range = map u A ⊔ map u S` is closed. rw [← Submodule.map_top, ← S_compl_A.symm.sup_eq_top, Submodule.map_sup] exact isClosed_sup_finiteDimensional _ _ uA_closed @@ -229,7 +227,7 @@ closed range. This is [N. Bourbaki, *Théories Spectrales*, Chapitre III, § 3, n° 1, Prop. 1][bourbaki2023]. -/ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) - [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] : + [A_cofg : A.CoFG] : (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ (IsStrictMap (u.domRestrict A) ∧ IsClosed (map u.toLinearMap A : Set F)) := by -- To reduce to step 4, we quotient by `N := A ⊓ u.ker`. Denoting by `π : E → E ⧸ N` @@ -295,7 +293,7 @@ section FiniteRank then `u` is strict with closed range if and only if `v` is strict with closed range. -/ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_eqOn [T2Space F] (u v : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed : IsClosed (A : Set E)) - [codim_A : FiniteDimensional 𝕜 (E ⧸ A)] (h_eqOn : EqOn u v A) : + [A_cofg : A.CoFG] (h_eqOn : EqOn u v A) : (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ (IsStrictMap v ∧ IsClosed (v.range : Set F)) := by simp_rw [u.isStrictMap_isClosed_range_iff_restrict A, @@ -316,7 +314,7 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_finiteRange (IsStrictMap v ∧ IsClosed (v.range : Set F)) := by let A := u.toLinearMap.eqLocus v.toLinearMap have A_closed : IsClosed (A : Set E) := u.isClosed_eqLocus v - have : FiniteDimensional 𝕜 (E ⧸ A) := equiv_iff_eqLocus_coFG.mp h_equiv + have : A.CoFG := equiv_iff_eqLocus_coFG.mp h_equiv exact ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_eqOn u v A A_closed (fun _ ↦ id) end FiniteRank From 4f002a2643d2a87f8f9937ffe39248dc6ea50bd1 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 9 Jul 2026 21:01:36 +0200 Subject: [PATCH 182/210] add eqOn_eqLocus --- Mathlib/Algebra/Module/Submodule/EqLocus.lean | 4 ++++ .../Analysis/Normed/Operator/Perturbation/StrictByFinite.lean | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Mathlib/Algebra/Module/Submodule/EqLocus.lean b/Mathlib/Algebra/Module/Submodule/EqLocus.lean index 9a6626da9d7b56..0691c6e537e6bb 100644 --- a/Mathlib/Algebra/Module/Submodule/EqLocus.lean +++ b/Mathlib/Algebra/Module/Submodule/EqLocus.lean @@ -68,6 +68,10 @@ theorem le_eqLocus {f g : M →ₛₗ[τ₁₂] M₂} {S : Submodule R M} : S ≤ eqLocus f g ↔ Set.EqOn f g S := Iff.rfl +theorem eqOn_eqLocus {f g : M →ₛₗ[τ₁₂] M₂} : + Set.EqOn f g (eqLocus f g) := + fun _ h ↦ h + variable {F : Type*} [FunLike F M M₂] [SemilinearMapClass F τ₁₂ M M₂] include τ₁₂ in diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 22a9cfb6ca7daf..d825ef2af6a09e 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -308,7 +308,7 @@ denoted `u.toLinearMap ≈ v.toLinearMap` in scope `LinearMap.FiniteRangeSetoid` strict with closed range if and only if `v` is strict with closed range. This is [N. Bourbaki, *Théories Spectrales*, Chapitre III, § 3, n° 1, Cor. 1][bourbaki2023]. -/ -public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_finiteRangeSetoid [T1Space F] +public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_finiteRangeSetoid [T2Space F] (u v : E →L[𝕜] F) (h_equiv : u.toLinearMap ≈ v.toLinearMap) : (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ (IsStrictMap v ∧ IsClosed (v.range : Set F)) := by @@ -327,7 +327,7 @@ open LinearMap.FiniteRangeSetoid that `u` is strict with closed range if and only if `B.mkQL ∘L u` is strict with closed range. This is [N. Bourbaki, *Théories Spectrales*, Chapitre III, § 3, n° 1, Cor. 2][bourbaki2023]. -/ -public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_quotient [T1Space F] +public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_quotient [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 F) [dim_A : FiniteDimensional 𝕜 A] (A_compl : ClosedComplemented A) : (IsStrictMap u ∧ IsClosed (u.range : Set F)) ↔ From 13c0e51f294c511580b920fc96021fd3eaef8538 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 9 Jul 2026 23:22:42 +0200 Subject: [PATCH 183/210] use eqOn_eqLocus --- .../Analysis/Normed/Operator/Perturbation/StrictByFinite.lean | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index d825ef2af6a09e..0172bbe1378d61 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -315,7 +315,8 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_finiteRange let A := u.toLinearMap.eqLocus v.toLinearMap have A_closed : IsClosed (A : Set E) := u.isClosed_eqLocus v have : A.CoFG := equiv_iff_eqLocus_coFG.mp h_equiv - exact ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_eqOn u v A A_closed (fun _ ↦ id) + exact ContinuousLinearMap.isStrictMap_isClosed_range_iff_of_eqOn u v A A_closed + LinearMap.eqOn_eqLocus end FiniteRank From dda794ee1b99a63d17b348dd88f1e6c04eabb43c Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 9 Jul 2026 23:57:12 +0200 Subject: [PATCH 184/210] use isClosed_range_of_isClosed_map_of_finiteDimensional_quotient --- .../Normed/Operator/Perturbation/StrictByFinite.lean | 12 ++++-------- Mathlib/Topology/Algebra/Module/FiniteDimension.lean | 11 +++++++++++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 0172bbe1378d61..833140348df9e5 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -204,14 +204,10 @@ theorem step4 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed -- To reduce to step 3, it suffices to show that, if `map u A` is closed, then so is `u.range`. suffices IsClosed (map u.toLinearMap A : Set F) → IsClosed (u.range : Set F) by grind only [step3] - -- So, we assume that `map u A` is closed. - intro uA_closed - -- Fix `S` an algebraic complement of `A` containing `u.ker`. It has finite dimension. - rcases h_ker.exists_isCompl with ⟨S, ker_le_S, S_compl_A⟩ - have : FiniteDimensional 𝕜 S := .of_fg <| A_cofg.fg_of_isCompl S_compl_A.symm - -- It follows that `u.range = map u A ⊔ map u S` is closed. - rw [← Submodule.map_top, ← S_compl_A.symm.sup_eq_top, Submodule.map_sup] - exact isClosed_sup_finiteDimensional _ _ uA_closed + -- So, we assume that `map u A` is closed, and we fix `S` an algebraic complement of `A`. + -- It has finite dimension. Then `u.range = map u A ⊔ map u S` is the supremum of + -- a closed subspace and a finite dimnsional subspace, hence it is closed. + exact u.toLinearMap.isClosed_range_of_isClosed_map_of_finiteDimensional_quotient /-! diff --git a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean index 9e16cef2540d80..2ecc959cdc91e9 100644 --- a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean +++ b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean @@ -553,6 +553,17 @@ theorem Submodule.isClosed_sup_finiteDimensional rw [← comap_map_mkQ] exact (map s.mkQ t).closed_of_finiteDimensional.preimage continuous_quot_mk +/-- Let `f : E →ₗ[𝕜] F` be a linear map, and `s` a subspace of `E` with finite codimension. +If the image of `s` by `f` is closed, the the range of `f` is closed. -/ +theorem LinearMap.isClosed_range_of_isClosed_map_of_finiteDimensional_quotient + {E : Type*} [AddCommGroup E] [Module 𝕜 E] {f : E →ₗ[𝕜] F} {s : Submodule 𝕜 E} + [hs : FiniteDimensional 𝕜 (E ⧸ s)] (h : IsClosed (s.map f : Set F)) : + IsClosed (f.range : Set F) := by + obtain ⟨t, s_compl_t⟩ := Submodule.exists_isCompl s + have : FiniteDimensional 𝕜 t := .of_fg <| Submodule.CoFG.fg_of_isCompl s_compl_t hs + rw [← Submodule.map_top, ← s_compl_t.sup_eq_top, Submodule.map_sup] + exact Submodule.isClosed_sup_finiteDimensional _ _ h + /-- An injective linear map with finite-dimensional domain is a closed embedding. -/ theorem LinearMap.isClosedEmbedding_of_injective [T2Space E] [FiniteDimensional 𝕜 E] [T2Space F] {f : E →ₗ[𝕜] F} (hf : LinearMap.ker f = ⊥) : IsClosedEmbedding f := From acf674e42b95f80e31f86672e79d3d2d525cfd62 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Thu, 9 Jul 2026 23:59:31 +0200 Subject: [PATCH 185/210] better doc --- .../Normed/Operator/Perturbation/StrictByFinite.lean | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 833140348df9e5..69e7cfe9fc06f8 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -204,11 +204,11 @@ theorem step4 [T2Space F] (u : E →L[𝕜] F) (A : Submodule 𝕜 E) (A_closed -- To reduce to step 3, it suffices to show that, if `map u A` is closed, then so is `u.range`. suffices IsClosed (map u.toLinearMap A : Set F) → IsClosed (u.range : Set F) by grind only [step3] - -- So, we assume that `map u A` is closed, and we fix `S` an algebraic complement of `A`. + -- This follows from a general lemma, but we recall the proof below for completeness + exact u.toLinearMap.isClosed_range_of_isClosed_map_of_finiteDimensional_quotient + -- Assume that `map u A` is closed, and fix `S` an algebraic complement of `A`. -- It has finite dimension. Then `u.range = map u A ⊔ map u S` is the supremum of -- a closed subspace and a finite dimnsional subspace, hence it is closed. - exact u.toLinearMap.isClosed_range_of_isClosed_map_of_finiteDimensional_quotient - /-! ### Step 5 From e5d83c4e41e80e06462c25f92147c5b6dbca82e1 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 00:20:15 +0200 Subject: [PATCH 186/210] reorganize step 5 --- .../Operator/Perturbation/StrictByFinite.lean | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean index 69e7cfe9fc06f8..d9ec86cb0457d4 100644 --- a/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean +++ b/Mathlib/Analysis/Normed/Operator/Perturbation/StrictByFinite.lean @@ -232,11 +232,11 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Sp set π : E →L[𝕜] E ⧸ N := N.mkQL set v : E ⧸ N →L[𝕜] F := N.liftQL u inf_le_right have π_quot : IsOpenQuotientMap π := N.isOpenQuotientMap_mkQL - have v_comp_π_eq_u : v ∘L π = u := rfl + have u_eq : u = v ∘L π := rfl -- We also consider the submodule `B := map π A` of `E ⧸ N`. It has finite codimension and, -- by construction, it is disjoint from the kernel of `v`. set B : Submodule 𝕜 (E ⧸ N) := map N.mkQ A - have codim_B : FiniteDimensional 𝕜 ((E ⧸ N) ⧸ B) := + have B_cofg : B.CoFG := quotientQuotientEquivQuotient N A inf_le_left |>.symm.finiteDimensional have v_ker : Disjoint v.ker B := by simp [disjoint_iff, v, B, toLinearMap_liftQL, ker_liftQ, @@ -246,21 +246,17 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Sp have A_mapsTo_B : MapsTo π A B := fun _ ↦ by simp [← comap_B] have B_closed : IsClosed (B : Set <| E ⧸ N) := by rwa [← π_quot.isQuotientMap.isClosed_preimage, ← π.coe_coe, ← comap_coe, comap_B] - -- Thus, we can apply step 4 to `v`: we get that `v` is strict with closed range if + -- Thus, we can apply step 4 to `v` and `B`: we get that `v` is strict with closed range if -- and only if `v.domRestrict B` is strict with closed range. have step4_output : (IsStrictMap v ∧ IsClosed (v.range : Set F)) ↔ - (IsStrictMap (v.domRestrict B) ∧ IsClosed (map v.toLinearMap B : Set F)) := by - simp [step4 v B B_closed v_ker, coe_domRestrict, ← range_restrict] + (IsStrictMap (v.domRestrict B) ∧ IsClosed (map v.toLinearMap B : Set F)) := + step4 v B B_closed v_ker -- Now, we wish to reduce our statement about `u` and `u.domRestrict A` -- to what we know about `v` and `v.domRestrict B`. -- First, it is clear that `range u = range v` and `map u A = map v B`. have range_eq : v.range = u.range := range_liftQ _ _ _ have image_eq : map v.toLinearMap B = map u.toLinearMap A := by - simp [B, ← v_comp_π_eq_u, π, ← map_comp] - -- Furthermore, since `π` is a quotient map and `u = v ∘ π`, we have that `u` is strict - -- if and only if `v` is strict. - have strict_iff : IsStrictMap u ↔ IsStrictMap v := by - rw [← v_comp_π_eq_u, coe_comp, ← π_quot.isQuotientMap.isStrictMap_iff] + simp [B, u_eq, π, ← map_comp] -- Now, recall the equality `A = comap π B`; it ensures that the restriction -- `π' : A → B` of the open quotient map `π` is *still* an (open) quotient map. set π' : A →L[𝕜] B := π.restrict A_mapsTo_B @@ -268,14 +264,17 @@ public theorem ContinuousLinearMap.isStrictMap_isClosed_range_iff_restrict [T2Sp let φ : (N.mkQL ⁻¹' B) ≃ₜ A := .setCongr congr(SetLike.coe $comap_B) exact N.isOpenQuotientMap_mkQL.restrictPreimage B |>.comp φ.symm.isOpenQuotientMap - have v_comp_π'_eq_u : v.domRestrict B ∘L π' = u.domRestrict A := rfl - -- Because `v.domRestrict B ∘ π' = u.domRestrict A`, it follows that `u.domRestrict A` - -- is strict if and only if `v.domRestrict B` is strict. - have strict_iff_restrict : IsStrictMap (u.domRestrict A) ↔ IsStrictMap (v.domRestrict B) := by - rw [← v_comp_π'_eq_u, coe_comp, ← π'_quot.isQuotientMap.isStrictMap_iff] - -- Thus, we are done! - rw [strict_iff, strict_iff_restrict, ← range_eq, ← image_eq] - exact step4_output + -- Note that `u.domRestrict A` factors as `v.domRestrict B ∘ π'`. + have u_restr_eq : u.domRestrict A = v.domRestrict B ∘L π' := rfl + -- We conclude by invoking `IsQuotientMap.isStrictMap_iff` twice, to get that strictness of + -- `u` (resp. `u.domRestrict A`) is equivalent to strictness of `v` (resp. `v.domRestrict B`). + calc IsStrictMap u ∧ IsClosed (u.range : Set F) + ↔ IsStrictMap v ∧ IsClosed (v.range : Set F) := by + rw [← range_eq, u_eq, coe_comp, π_quot.isQuotientMap.isStrictMap_iff] + _ ↔ IsStrictMap (v.domRestrict B) ∧ IsClosed (map v.toLinearMap B : Set F) := + step4_output + _ ↔ IsStrictMap (u.domRestrict A) ∧ IsClosed (map u.toLinearMap A : Set F) := by + rw [← image_eq, u_restr_eq, coe_comp, π'_quot.isQuotientMap.isStrictMap_iff] end FiniteCodimSubspace From c32a67f1a0504943a84be5d2ebf27a923b6bc12e Mon Sep 17 00:00:00 2001 From: faenuccio Date: Fri, 10 Jul 2026 10:06:29 +0200 Subject: [PATCH 187/210] introduced FredholmPackage and Refactored --- Mathlib/Analysis/FredholmOperator.lean | 171 +++++++++++++++---------- 1 file changed, 104 insertions(+), 67 deletions(-) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index 4bb4d6082c2936..986bc3298db559 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -54,51 +54,67 @@ section FredholmDecomposition variable [ContinuousSub E] -structure FredholmDecomposition (u : E →L[𝕜] F) where - dom₀ : Submodule 𝕜 E - dom₁ : Submodule 𝕜 E - finite_dom₀ : FiniteDimensional 𝕜 dom₀ - isTopCompl_dom : IsTopCompl dom₀ dom₁ - codom₀ : Submodule 𝕜 F - codom₁ : Submodule 𝕜 F - finite_codom₀ : FiniteDimensional 𝕜 codom₀ - isTopCompl_codom : IsTopCompl codom₀ codom₁ - equiv : dom₁ ≃L[𝕜] codom₁ - eq_equiv' : u = codom₁.subtypeL ∘L equiv ∘L (dom₁.projectionOntoL dom₀ isTopCompl_dom.symm) - -abbrev FredholmDecomposition.domProj {u : E →L[𝕜] F} (dec : FredholmDecomposition u) : - E →L[𝕜] dec.dom₁ := dec.dom₁.projectionOntoL dec.dom₀ dec.isTopCompl_dom.symm +variable (𝕜 E) in +structure FredholmDecomposition where + X₁ : Submodule 𝕜 E + X₂ : Submodule 𝕜 E + topCompl : IsTopCompl X₁ X₂ + fin_dim : FiniteDimensional 𝕜 X₂ + +structure FredholmPackage (u : E →L[𝕜] F) where + -- dom₀ : Submodule 𝕜 E + -- dom₁ : Submodule 𝕜 E + -- finite_dom₀ : FiniteDimensional 𝕜 dom₀ + -- isTopCompl_dom : IsTopCompl dom₀ dom₁ + -- codom₀ : Submodule 𝕜 F + -- codom₁ : Submodule 𝕜 F + FD_E : FredholmDecomposition 𝕜 E + FD_F : FredholmDecomposition 𝕜 F + -- finite_codom₀ : FiniteDimensional 𝕜 codom₀ + -- isTopCompl_codom : IsTopCompl codom₀ codom₁ + -- equiv : dom₁ ≃L[𝕜] codom₁ + equiv : FD_E.X₁ ≃L[𝕜] FD_F.X₁ + -- eq_equiv' : u = codom₁.subtypeL ∘L equiv ∘L (dom₁.projectionOntoL dom₀ isTopCompl_dom.symm) + eq_equiv' : u = FD_F.X₁.subtypeL ∘L equiv ∘L (FD_E.X₁.projectionOntoL FD_E.X₂ FD_E.topCompl) +-- **FAE** J'ai laissé ton `'` mais je ne comprends pas pourquoi tu ne veux pas un `eq_equiv` (je m'en fous en vrai) + +abbrev FredholmPackage.domProj {u : E →L[𝕜] F} (pkg : FredholmPackage u) : + E →L[𝕜] pkg.FD_E.X₁ := pkg.FD_E.X₁.projectionOntoL pkg.FD_E.X₂ pkg.FD_E.topCompl + -- E →L[𝕜] dec.dom₁ := dec.dom₁.projectionOntoL dec.dom₀ dec.isTopCompl_dom.symm + +-- variable [ContinuousSub F] in +abbrev FredholmPackage.codomProj {u : E →L[𝕜] F} (pkg : FredholmPackage u) : + -- F →L[𝕜] dec.codom₁ := dec.codom₁.projectionOntoL dec.codom₀ dec.isTopCompl_codom.symm + F →L[𝕜] pkg.FD_F.X₁ := pkg.FD_F.X₁.projectionOntoL pkg.FD_F.X₂ pkg.FD_F.topCompl + + +lemma FredholmPackage.eq_equiv {u : E →L[𝕜] F} (pkg : FredholmPackage u) : + -- u = dec.codom₁.subtypeL ∘L dec.equiv ∘L dec.domProj := dec.eq_equiv' + u = pkg.FD_F.X₁.subtypeL ∘L pkg.equiv ∘L pkg.domProj := pkg.eq_equiv' + +lemma FredholmPackage.ker_eq {u : E →L[𝕜] F} (pkg : FredholmPackage u) : + u.ker = pkg.FD_E.X₂ := by simp [pkg.eq_equiv, ker_comp] + +lemma FredholmPackage.range_eq {u : E →L[𝕜] F} (pkg : FredholmPackage u) : + u.range = pkg.FD_F.X₁ := by + simp [pkg.eq_equiv, range_comp] variable [ContinuousSub F] in -abbrev FredholmDecomposition.codomProj {u : E →L[𝕜] F} (dec : FredholmDecomposition u) : - F →L[𝕜] dec.codom₁ := dec.codom₁.projectionOntoL dec.codom₀ dec.isTopCompl_codom.symm - -lemma FredholmDecomposition.eq_equiv {u : E →L[𝕜] F} (dec : FredholmDecomposition u) : - u = dec.codom₁.subtypeL ∘L dec.equiv ∘L dec.domProj := - dec.eq_equiv' - -lemma FredholmDecomposition.ker_eq {u : E →L[𝕜] F} (dec : FredholmDecomposition u) : - u.ker = dec.dom₀ := by - simp [dec.eq_equiv, ker_comp] - -lemma FredholmDecomposition.range_eq {u : E →L[𝕜] F} (dec : FredholmDecomposition u) : - u.range = dec.codom₁ := by - simp [dec.eq_equiv, range_comp] - -variable [ContinuousSub F] in -def FredholmDecomposition.quasiInverse {u : E →L[𝕜] F} (dec : FredholmDecomposition u) : +def FredholmPackage.quasiInverse {u : E →L[𝕜] F} (pkg : FredholmPackage u) : F →L[𝕜] E := - dec.dom₁.subtypeL ∘L dec.equiv.symm ∘L dec.codomProj - -variable [ContinuousSub F] in -lemma FredholmDecomposition.isQuasiInverse {u : E →L[𝕜] F} (dec : FredholmDecomposition u) : - u.IsQuasiInverse dec.quasiInverse := by - nth_rw 1 [dec.eq_equiv, quasiInverse] - have hdom : IsQuasiInverse dec.dom₁.subtype dec.domProj := - have := dec.finite_dom₀ + -- dec.dom₁.subtypeL ∘L dec.equiv.symm ∘L dec.codomProj + pkg.FD_E.X₁.subtypeL ∘L pkg.equiv.symm ∘L pkg.codomProj + +-- variable [ContinuousSub F] in +lemma FredholmPackage.isQuasiInverse {u : E →L[𝕜] F} (pkg : FredholmPackage u) : + u.IsQuasiInverse pkg.quasiInverse := by + nth_rw 1 [pkg.eq_equiv, quasiInverse] + -- have hdom : IsQuasiInverse dec.dom₁.subtype dec.domProj := + have hdom : IsQuasiInverse pkg.FD_E.X₁.subtype pkg.domProj := + have := pkg.FD_E.fin_dim isQuasiInverse_subtype_projectionOnto _ - have hcodom : IsQuasiInverse dec.codom₁.subtype dec.codomProj := - have := dec.finite_codom₀ + have hcodom : IsQuasiInverse pkg.FD_F.X₁.subtype pkg.codomProj := + have := pkg.FD_F.fin_dim isQuasiInverse_subtype_projectionOnto _ refine .of_comp_left hcodom.symm <| .of_comp_right hdom ?_ simp_rw [domProj, codomProj, toLinearMap_comp, toLinearMap_subtypeL, toLinearMap_projectionOntoL, @@ -166,35 +182,56 @@ theorem IsFredholm.of_isInvertible_restrict {u : E →L[𝕜] F} · exact .of_disjoint_of_finiteDimensional_quotient E₁_closed disj.symm omit [ContinuousSMul 𝕜 E] in -def IsFredholm.fredholmDecomposition {u : E →L[𝕜] F} - (u_fred : IsFredholm u) {dom₁ : Submodule 𝕜 E} {codom₀ : Submodule 𝕜 F} - (h_dom : IsTopCompl u.ker dom₁) (h_codom : IsTopCompl codom₀ u.range) : - FredholmDecomposition u := - { dom₀ := u.ker - dom₁ := dom₁ - finite_dom₀ := u_fred.finite_ker - isTopCompl_dom := h_dom - codom₀ := codom₀ - codom₁ := u.range - finite_codom₀ := Module.Finite.of_fg <| u_fred.finite_coker.fg_of_isCompl h_codom.isCompl.symm - isTopCompl_codom := h_codom - equiv := - letI Φ : dom₁ ≃L[𝕜] E ⧸ u.ker := u.ker.quotientEquivOfIsTopCompl dom₁ h_dom |>.symm - letI Ψ : (E ⧸ u.ker) ≃L[𝕜] u.range := .quotKerEquivRange u.toLinearMap u_fred.isStrictMap - Φ.trans Ψ - eq_equiv' := by - refine LinearMap.ext_on_codisjoint h_dom.isCompl.codisjoint ?_ ?_ - · intro x (hx : u x = 0) - simp [hx, projection_apply_of_mem_right] - · intro x (hx : x ∈ dom₁) - simp [hx, projection_apply_of_mem_left, ContinuousLinearEquiv.quotKerEquivRange] } +def IsFredholm.fredholmPackage {u : E →L[𝕜] F} + (u_fred : IsFredholm u) {dom₁ : Submodule 𝕜 E} {codom₂ : Submodule 𝕜 F} + (h_dom : IsTopCompl dom₁ u.ker) (h_codom : IsTopCompl u.range codom₂) : + FredholmPackage u where + FD_E := { + X₁ := dom₁ + X₂ := u.ker + topCompl := h_dom + fin_dim := u_fred.finite_ker } + FD_F := { + X₁ := u.range + X₂ := codom₂ + topCompl := h_codom + fin_dim := Module.Finite.of_fg <| u_fred.finite_coker.fg_of_isCompl h_codom.isCompl } + equiv := + letI Φ : dom₁ ≃L[𝕜] E ⧸ u.ker := u.ker.quotientEquivOfIsTopCompl dom₁ h_dom.symm |>.symm + letI Ψ : (E ⧸ u.ker) ≃L[𝕜] u.range := .quotKerEquivRange u.toLinearMap u_fred.isStrictMap + Φ.trans Ψ + eq_equiv' := by + refine LinearMap.ext_on_codisjoint h_dom.isCompl.codisjoint ?_ ?_ + · intro x (hx : x ∈ dom₁) + simp [hx, projection_apply_of_mem_left, ContinuousLinearEquiv.quotKerEquivRange] + · intro x (hx : u x = 0) + simp [hx, projection_apply_of_mem_right] + + -- { dom₀ := u.ker + -- dom₁ := dom₁ + -- finite_dom₀ := u_fred.finite_ker + -- isTopCompl_dom := h_dom + -- codom₀ := codom₀ + -- codom₁ := u.range + -- finite_codom₀ := Module.Finite.of_fg <| u_fred.finite_coker.fg_of_isCompl h_codom.isCompl.symm + -- isTopCompl_codom := h_codom + -- equiv := + -- letI Φ : dom₁ ≃L[𝕜] E ⧸ u.ker := u.ker.quotientEquivOfIsTopCompl dom₁ h_dom |>.symm + -- letI Ψ : (E ⧸ u.ker) ≃L[𝕜] u.range := .quotKerEquivRange u.toLinearMap u_fred.isStrictMap + -- Φ.trans Ψ + -- eq_equiv' := by + -- refine LinearMap.ext_on_codisjoint h_dom.isCompl.codisjoint ?_ ?_ + -- · intro x (hx : u x = 0) + -- simp [hx, projection_apply_of_mem_right] + -- · intro x (hx : x ∈ dom₁) + -- simp [hx, projection_apply_of_mem_left, ContinuousLinearEquiv.quotKerEquivRange] } omit [ContinuousSMul 𝕜 E] in theorem IsFredholm.nonempty_fredholmDecomposition {u : E →L[𝕜] F} - (u_fred : IsFredholm u) : Nonempty (FredholmDecomposition u) := by - obtain ⟨codom₀, h_codom⟩ := u_fred.closedComplemented_range.exists_isTopCompl + (u_fred : IsFredholm u) : Nonempty (FredholmPackage u) := by + obtain ⟨codom₂, h_codom⟩ := u_fred.closedComplemented_range.exists_isTopCompl obtain ⟨dom₁, h_dom⟩ := u_fred.closedComplemented_ker.exists_isTopCompl - exact ⟨u_fred.fredholmDecomposition h_dom h_codom.symm⟩ + exact ⟨u_fred.fredholmPackage h_dom.symm h_codom⟩ variable [T2Space E] [T2Space F] @@ -206,7 +243,7 @@ theorem isFredholmTFAE (u : E →L[𝕜] F) : List.TFAE IsClosed (E₁ : Set E) ∧ IsClosed (F₁ : Set F) ∧ E₁.CoFG ∧ F₁.CoFG ∧ ∃ h : MapsTo u E₁ F₁, (u.restrict h).IsInvertible, - Nonempty (FredholmDecomposition u) + Nonempty (FredholmPackage u) ] := by tfae_have 1 → 4 := IsFredholm.nonempty_fredholmDecomposition tfae_have 4 → 2 := by From 2e6a72f847b7b7babf9898eb639a1a2915dc2860 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 11:49:32 +0200 Subject: [PATCH 188/210] back to 0 + FD.proj + renames --- Mathlib/Analysis/FredholmOperator.lean | 117 ++++++++----------------- 1 file changed, 35 insertions(+), 82 deletions(-) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index 986bc3298db559..86aa35108694f4 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -52,74 +52,46 @@ end IsFredholm section FredholmDecomposition -variable [ContinuousSub E] - variable (𝕜 E) in structure FredholmDecomposition where + X₀ : Submodule 𝕜 E X₁ : Submodule 𝕜 E - X₂ : Submodule 𝕜 E - topCompl : IsTopCompl X₁ X₂ - fin_dim : FiniteDimensional 𝕜 X₂ + isTopCompl : IsTopCompl X₁ X₀ + fin_dim_X₀ : FiniteDimensional 𝕜 X₀ + +abbrev FredholmDecomposition.proj (dec : FredholmDecomposition 𝕜 E) : + E →L[𝕜] dec.X₁ := dec.X₁.projectionOntoL dec.X₀ dec.isTopCompl structure FredholmPackage (u : E →L[𝕜] F) where - -- dom₀ : Submodule 𝕜 E - -- dom₁ : Submodule 𝕜 E - -- finite_dom₀ : FiniteDimensional 𝕜 dom₀ - -- isTopCompl_dom : IsTopCompl dom₀ dom₁ - -- codom₀ : Submodule 𝕜 F - -- codom₁ : Submodule 𝕜 F - FD_E : FredholmDecomposition 𝕜 E - FD_F : FredholmDecomposition 𝕜 F - -- finite_codom₀ : FiniteDimensional 𝕜 codom₀ - -- isTopCompl_codom : IsTopCompl codom₀ codom₁ - -- equiv : dom₁ ≃L[𝕜] codom₁ - equiv : FD_E.X₁ ≃L[𝕜] FD_F.X₁ - -- eq_equiv' : u = codom₁.subtypeL ∘L equiv ∘L (dom₁.projectionOntoL dom₀ isTopCompl_dom.symm) - eq_equiv' : u = FD_F.X₁.subtypeL ∘L equiv ∘L (FD_E.X₁.projectionOntoL FD_E.X₂ FD_E.topCompl) --- **FAE** J'ai laissé ton `'` mais je ne comprends pas pourquoi tu ne veux pas un `eq_equiv` (je m'en fous en vrai) - -abbrev FredholmPackage.domProj {u : E →L[𝕜] F} (pkg : FredholmPackage u) : - E →L[𝕜] pkg.FD_E.X₁ := pkg.FD_E.X₁.projectionOntoL pkg.FD_E.X₂ pkg.FD_E.topCompl - -- E →L[𝕜] dec.dom₁ := dec.dom₁.projectionOntoL dec.dom₀ dec.isTopCompl_dom.symm - --- variable [ContinuousSub F] in -abbrev FredholmPackage.codomProj {u : E →L[𝕜] F} (pkg : FredholmPackage u) : - -- F →L[𝕜] dec.codom₁ := dec.codom₁.projectionOntoL dec.codom₀ dec.isTopCompl_codom.symm - F →L[𝕜] pkg.FD_F.X₁ := pkg.FD_F.X₁.projectionOntoL pkg.FD_F.X₂ pkg.FD_F.topCompl - - -lemma FredholmPackage.eq_equiv {u : E →L[𝕜] F} (pkg : FredholmPackage u) : - -- u = dec.codom₁.subtypeL ∘L dec.equiv ∘L dec.domProj := dec.eq_equiv' - u = pkg.FD_F.X₁.subtypeL ∘L pkg.equiv ∘L pkg.domProj := pkg.eq_equiv' + dec_dom : FredholmDecomposition 𝕜 E + dec_codom : FredholmDecomposition 𝕜 F + equiv : dec_dom.X₁ ≃L[𝕜] dec_codom.X₁ + eq_equiv : u = dec_codom.X₁.subtypeL ∘L equiv ∘L dec_dom.proj lemma FredholmPackage.ker_eq {u : E →L[𝕜] F} (pkg : FredholmPackage u) : - u.ker = pkg.FD_E.X₂ := by simp [pkg.eq_equiv, ker_comp] + u.ker = pkg.dec_dom.X₀ := by simp [pkg.eq_equiv, ker_comp] lemma FredholmPackage.range_eq {u : E →L[𝕜] F} (pkg : FredholmPackage u) : - u.range = pkg.FD_F.X₁ := by + u.range = pkg.dec_codom.X₁ := by simp [pkg.eq_equiv, range_comp] -variable [ContinuousSub F] in def FredholmPackage.quasiInverse {u : E →L[𝕜] F} (pkg : FredholmPackage u) : F →L[𝕜] E := - -- dec.dom₁.subtypeL ∘L dec.equiv.symm ∘L dec.codomProj - pkg.FD_E.X₁.subtypeL ∘L pkg.equiv.symm ∘L pkg.codomProj + pkg.dec_dom.X₁.subtypeL ∘L pkg.equiv.symm ∘L pkg.dec_codom.proj --- variable [ContinuousSub F] in lemma FredholmPackage.isQuasiInverse {u : E →L[𝕜] F} (pkg : FredholmPackage u) : u.IsQuasiInverse pkg.quasiInverse := by nth_rw 1 [pkg.eq_equiv, quasiInverse] - -- have hdom : IsQuasiInverse dec.dom₁.subtype dec.domProj := - have hdom : IsQuasiInverse pkg.FD_E.X₁.subtype pkg.domProj := - have := pkg.FD_E.fin_dim + have hdom : IsQuasiInverse pkg.dec_dom.X₁.subtype pkg.dec_dom.proj := + have := pkg.dec_dom.fin_dim_X₀ isQuasiInverse_subtype_projectionOnto _ - have hcodom : IsQuasiInverse pkg.FD_F.X₁.subtype pkg.codomProj := - have := pkg.FD_F.fin_dim + have hcodom : IsQuasiInverse pkg.dec_codom.X₁.subtype pkg.dec_codom.proj := + have := pkg.dec_codom.fin_dim_X₀ isQuasiInverse_subtype_projectionOnto _ refine .of_comp_left hcodom.symm <| .of_comp_right hdom ?_ - simp_rw [domProj, codomProj, toLinearMap_comp, toLinearMap_subtypeL, toLinearMap_projectionOntoL, - LinearMap.comp_assoc, projectionOnto_comp_subtype, LinearMap.comp_id, - ← LinearMap.comp_assoc, projectionOnto_comp_subtype, LinearMap.id_comp] + simp_rw [FredholmDecomposition.proj, toLinearMap_comp, toLinearMap_subtypeL, + toLinearMap_projectionOntoL, LinearMap.comp_assoc, projectionOnto_comp_subtype, + LinearMap.comp_id, ← LinearMap.comp_assoc, projectionOnto_comp_subtype, LinearMap.id_comp] simp [IsQuasiInverse, IsLeftQuasiInverse, IsRightQuasiInverse] end FredholmDecomposition @@ -183,55 +155,36 @@ theorem IsFredholm.of_isInvertible_restrict {u : E →L[𝕜] F} omit [ContinuousSMul 𝕜 E] in def IsFredholm.fredholmPackage {u : E →L[𝕜] F} - (u_fred : IsFredholm u) {dom₁ : Submodule 𝕜 E} {codom₂ : Submodule 𝕜 F} - (h_dom : IsTopCompl dom₁ u.ker) (h_codom : IsTopCompl u.range codom₂) : + (u_fred : IsFredholm u) {dom₁ : Submodule 𝕜 E} {codom₀ : Submodule 𝕜 F} + (h_dom : IsTopCompl u.ker dom₁) (h_codom : IsTopCompl u.range codom₀) : FredholmPackage u where - FD_E := { + dec_dom := { + X₀ := u.ker X₁ := dom₁ - X₂ := u.ker - topCompl := h_dom - fin_dim := u_fred.finite_ker } - FD_F := { + isTopCompl := h_dom.symm + fin_dim_X₀ := u_fred.finite_ker } + dec_codom := { + X₀ := codom₀ X₁ := u.range - X₂ := codom₂ - topCompl := h_codom - fin_dim := Module.Finite.of_fg <| u_fred.finite_coker.fg_of_isCompl h_codom.isCompl } + isTopCompl := h_codom + fin_dim_X₀ := .of_fg <| u_fred.finite_coker.fg_of_isCompl h_codom.isCompl } equiv := - letI Φ : dom₁ ≃L[𝕜] E ⧸ u.ker := u.ker.quotientEquivOfIsTopCompl dom₁ h_dom.symm |>.symm + letI Φ : dom₁ ≃L[𝕜] E ⧸ u.ker := u.ker.quotientEquivOfIsTopCompl dom₁ h_dom |>.symm letI Ψ : (E ⧸ u.ker) ≃L[𝕜] u.range := .quotKerEquivRange u.toLinearMap u_fred.isStrictMap Φ.trans Ψ - eq_equiv' := by + eq_equiv := by refine LinearMap.ext_on_codisjoint h_dom.isCompl.codisjoint ?_ ?_ - · intro x (hx : x ∈ dom₁) - simp [hx, projection_apply_of_mem_left, ContinuousLinearEquiv.quotKerEquivRange] · intro x (hx : u x = 0) simp [hx, projection_apply_of_mem_right] - - -- { dom₀ := u.ker - -- dom₁ := dom₁ - -- finite_dom₀ := u_fred.finite_ker - -- isTopCompl_dom := h_dom - -- codom₀ := codom₀ - -- codom₁ := u.range - -- finite_codom₀ := Module.Finite.of_fg <| u_fred.finite_coker.fg_of_isCompl h_codom.isCompl.symm - -- isTopCompl_codom := h_codom - -- equiv := - -- letI Φ : dom₁ ≃L[𝕜] E ⧸ u.ker := u.ker.quotientEquivOfIsTopCompl dom₁ h_dom |>.symm - -- letI Ψ : (E ⧸ u.ker) ≃L[𝕜] u.range := .quotKerEquivRange u.toLinearMap u_fred.isStrictMap - -- Φ.trans Ψ - -- eq_equiv' := by - -- refine LinearMap.ext_on_codisjoint h_dom.isCompl.codisjoint ?_ ?_ - -- · intro x (hx : u x = 0) - -- simp [hx, projection_apply_of_mem_right] - -- · intro x (hx : x ∈ dom₁) - -- simp [hx, projection_apply_of_mem_left, ContinuousLinearEquiv.quotKerEquivRange] } + · intro x (hx : x ∈ dom₁) + simp [hx, projection_apply_of_mem_left, ContinuousLinearEquiv.quotKerEquivRange] omit [ContinuousSMul 𝕜 E] in theorem IsFredholm.nonempty_fredholmDecomposition {u : E →L[𝕜] F} (u_fred : IsFredholm u) : Nonempty (FredholmPackage u) := by obtain ⟨codom₂, h_codom⟩ := u_fred.closedComplemented_range.exists_isTopCompl obtain ⟨dom₁, h_dom⟩ := u_fred.closedComplemented_ker.exists_isTopCompl - exact ⟨u_fred.fredholmPackage h_dom.symm h_codom⟩ + exact ⟨u_fred.fredholmPackage h_dom h_codom⟩ variable [T2Space E] [T2Space F] From fb688d6dc799a562d63d23c0f64aa8dbd4b687c0 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 12:51:37 +0200 Subject: [PATCH 189/210] Good start on documentation --- Mathlib/Analysis/FredholmOperator.lean | 72 ++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 9 deletions(-) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index 86aa35108694f4..ce0cdb8731a49e 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -13,6 +13,12 @@ public import Mathlib.Algebra.Module.LinearMap.Index /-! # Fredholm operators between topological vector spaces + +Fix `𝕜` a complete `NontriviallyNormedField`, and `E`, `F` be two Hausdorff topological vector +spaces over `𝕜`. + +In this file, we define what it means for a continuous linear map `T : E →L[𝕜] F` to be +a **Fredholm operator**. -/ @[expose] public noncomputable section @@ -35,6 +41,14 @@ section DefTFAE section IsFredholm +/-- A continuous linear map `u : E →L[𝕜] F` is a **Fredholm operator** if it is strict, +its range is closed and has finite codimension, and its kernel is (topologically) complemented and +has finite dimension. + +See also `isFredholm_tfae` for other equivalent characterizations. +We will also prove later (not in Mathlib yet) that for maps between Banach (or even Fréchet) +spaces, all the conditions follow from the kernel and cokernel having finite dimension. +-/ structure IsFredholm (u : E →L[𝕜] F) : Prop where isStrictMap : IsStrictMap u isClosed_range : IsClosed (u.range : Set F) @@ -53,15 +67,38 @@ end IsFredholm section FredholmDecomposition variable (𝕜 E) in +/-- A **Fredholm decomposition** of a topological vector space `E` is the data of two subspaces +`X₀` and `X₁` which are topological complements, and where `X₀` is finite dimensional. + +Note that we purposefully use the index `₀` for the "inessential" (i.e finite dimensional) +part of the decomposition. -/ structure FredholmDecomposition where X₀ : Submodule 𝕜 E X₁ : Submodule 𝕜 E isTopCompl : IsTopCompl X₁ X₀ - fin_dim_X₀ : FiniteDimensional 𝕜 X₀ + finite_X₀ : FiniteDimensional 𝕜 X₀ +/-- Given a fredhom decomposition `dec` of the space `E`, `dec.proj` is the (continuous linear) +projection onto the "essential part" `dec.X₁` along the "inessential part" `dec.X₀`. +This is a Fredholm operator. -/ abbrev FredholmDecomposition.proj (dec : FredholmDecomposition 𝕜 E) : E →L[𝕜] dec.X₁ := dec.X₁.projectionOntoL dec.X₀ dec.isTopCompl +/-- Let `u : E →L[𝕜] F` be a continuous linear map. A **Fredholm package** for `u` is the data of +Fredholm decompositions `dec_dom` and `dec_codom` of `E` and `F` respectively, together with +a continuous linear equivalence `equiv : dec_dom.X₁ ≃ₗ[𝕜] dec_codom.X₁` between the "essential" +(i.e finite codimension) parts of these decompositions, such that `u` equals the composition +`u = dec_codom.X₁.subtypeL ∘L equiv ∘L dec_dom.proj`. In other words, in these +"essential ⊕ inessential" decompositions, the matrix of `u` is +``` +equiv 0 +0 0 +``` + +We will show in `isFredholm_tfae` that an operator is Fredholm if and only if it admits +a Fredholm package. In practice, the condition that `u` is Fredholm is always easier to +prove, so if you need a Fredholm package you should probably get it from +`IsFredholm.nonempty_fredholmPackage` or `IsFredholm.fredholmPackage`. -/ structure FredholmPackage (u : E →L[𝕜] F) where dec_dom : FredholmDecomposition 𝕜 E dec_codom : FredholmDecomposition 𝕜 F @@ -75,18 +112,20 @@ lemma FredholmPackage.range_eq {u : E →L[𝕜] F} (pkg : FredholmPackage u) : u.range = pkg.dec_codom.X₁ := by simp [pkg.eq_equiv, range_comp] +/-- The data of a Fredholm package for `u` determines a canonical quasi-inverse of `u`. -/ def FredholmPackage.quasiInverse {u : E →L[𝕜] F} (pkg : FredholmPackage u) : F →L[𝕜] E := pkg.dec_dom.X₁.subtypeL ∘L pkg.equiv.symm ∘L pkg.dec_codom.proj +/-- The data of a Fredholm package for `u` determines a canonical quasi-inverse of `u`. -/ lemma FredholmPackage.isQuasiInverse {u : E →L[𝕜] F} (pkg : FredholmPackage u) : u.IsQuasiInverse pkg.quasiInverse := by nth_rw 1 [pkg.eq_equiv, quasiInverse] have hdom : IsQuasiInverse pkg.dec_dom.X₁.subtype pkg.dec_dom.proj := - have := pkg.dec_dom.fin_dim_X₀ + have := pkg.dec_dom.finite_X₀ isQuasiInverse_subtype_projectionOnto _ have hcodom : IsQuasiInverse pkg.dec_codom.X₁.subtype pkg.dec_codom.proj := - have := pkg.dec_codom.fin_dim_X₀ + have := pkg.dec_codom.finite_X₀ isQuasiInverse_subtype_projectionOnto _ refine .of_comp_left hcodom.symm <| .of_comp_right hdom ?_ simp_rw [FredholmDecomposition.proj, toLinearMap_comp, toLinearMap_subtypeL, @@ -128,7 +167,7 @@ variable [T2Space F] in subspaces `E₁` and `F₁`. Then `u` is Fredholm. In fact it is enough to assume that the restriction `E₁ →L[𝕜] F₁` is Fredholm, see -`IsFredholm.of_restrict`. -/ +`IsFredholm.of_restrict` (not in Mathlib yet). -/ theorem IsFredholm.of_isInvertible_restrict {u : E →L[𝕜] F} {E₁ : Submodule 𝕜 E} (E₁_closed : IsClosed (E₁ : Set E)) [E₁_coFG : E₁.CoFG] {F₁ : Submodule 𝕜 F} (F₁_closed : IsClosed (F₁ : Set F)) [F₁_coFG : F₁.CoFG] @@ -154,6 +193,13 @@ theorem IsFredholm.of_isInvertible_restrict {u : E →L[𝕜] F} · exact .of_disjoint_of_finiteDimensional_quotient E₁_closed disj.symm omit [ContinuousSMul 𝕜 E] in +/-- Let `u : E →L[𝕜] F` be a Fredholm operator. Given `dom₁` (resp. `codom₀`) be an arbitrary +topological complement of `u.ker` (resp. `u.range`), we get a `FredholmPackage` for `u` +by considering the decompositions `E = dom₁ ⊕ u.ker`, `F = u.range ⊕ codom₀`, and the isomorphism +`dom₁ ≃L[𝕜] u.range` induced by `u`. + +If you need control over the decompositions, this is the primary way to get a `FredholmPackage`. +Otherwise, see `IsFredholm.nonempty_fredholmPackage`. -/ def IsFredholm.fredholmPackage {u : E →L[𝕜] F} (u_fred : IsFredholm u) {dom₁ : Submodule 𝕜 E} {codom₀ : Submodule 𝕜 F} (h_dom : IsTopCompl u.ker dom₁) (h_codom : IsTopCompl u.range codom₀) : @@ -162,12 +208,12 @@ def IsFredholm.fredholmPackage {u : E →L[𝕜] F} X₀ := u.ker X₁ := dom₁ isTopCompl := h_dom.symm - fin_dim_X₀ := u_fred.finite_ker } + finite_X₀ := u_fred.finite_ker } dec_codom := { X₀ := codom₀ X₁ := u.range isTopCompl := h_codom - fin_dim_X₀ := .of_fg <| u_fred.finite_coker.fg_of_isCompl h_codom.isCompl } + finite_X₀ := .of_fg <| u_fred.finite_coker.fg_of_isCompl h_codom.isCompl } equiv := letI Φ : dom₁ ≃L[𝕜] E ⧸ u.ker := u.ker.quotientEquivOfIsTopCompl dom₁ h_dom |>.symm letI Ψ : (E ⧸ u.ker) ≃L[𝕜] u.range := .quotKerEquivRange u.toLinearMap u_fred.isStrictMap @@ -180,7 +226,11 @@ def IsFredholm.fredholmPackage {u : E →L[𝕜] F} simp [hx, projection_apply_of_mem_left, ContinuousLinearEquiv.quotKerEquivRange] omit [ContinuousSMul 𝕜 E] in -theorem IsFredholm.nonempty_fredholmDecomposition {u : E →L[𝕜] F} +/-- Every Fredholm operator admits a `FredholmPackage`. + +This is the primary way to get a `FredholmPackage` if you don't need control of the decompositions. +If you do, see `IsFredholm.fredholmPackage`. -/ +theorem IsFredholm.nonempty_fredholmPackage {u : E →L[𝕜] F} (u_fred : IsFredholm u) : Nonempty (FredholmPackage u) := by obtain ⟨codom₂, h_codom⟩ := u_fred.closedComplemented_range.exists_isTopCompl obtain ⟨dom₁, h_dom⟩ := u_fred.closedComplemented_ker.exists_isTopCompl @@ -188,7 +238,7 @@ theorem IsFredholm.nonempty_fredholmDecomposition {u : E →L[𝕜] F} variable [T2Space E] [T2Space F] -theorem isFredholmTFAE (u : E →L[𝕜] F) : List.TFAE +theorem isFredholm_tfae (u : E →L[𝕜] F) : List.TFAE [ IsFredholm u, ∃ v : F →L[𝕜] E, u.IsQuasiInverse v, @@ -198,7 +248,7 @@ theorem isFredholmTFAE (u : E →L[𝕜] F) : List.TFAE ∃ h : MapsTo u E₁ F₁, (u.restrict h).IsInvertible, Nonempty (FredholmPackage u) ] := by - tfae_have 1 → 4 := IsFredholm.nonempty_fredholmDecomposition + tfae_have 1 → 4 := IsFredholm.nonempty_fredholmPackage tfae_have 4 → 2 := by rintro ⟨dec⟩ exact ⟨dec.quasiInverse, dec.isQuasiInverse⟩ @@ -210,6 +260,10 @@ theorem isFredholmTFAE (u : E →L[𝕜] F) : List.TFAE exact .of_isInvertible_restrict E₁_closed F₁_closed u_mapsto u_invertible tfae_finish +theorem FredholmPackage.isFredholm {u : E →L[𝕜] F} (pkg : FredholmPackage u) : + IsFredholm u := + isFredholm_tfae u |>.out 3 0 |>.mp (Nonempty.intro pkg) + end DefTFAE end ContinuousLinearMap From 20bdb90b65887274fbb921bbca424d6b43f38480 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 13:25:10 +0200 Subject: [PATCH 190/210] Precise --- Mathlib/Analysis/FredholmOperator.lean | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index ce0cdb8731a49e..2d1800eb525d5c 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -47,7 +47,8 @@ has finite dimension. See also `isFredholm_tfae` for other equivalent characterizations. We will also prove later (not in Mathlib yet) that for maps between Banach (or even Fréchet) -spaces, all the conditions follow from the kernel and cokernel having finite dimension. +spaces over `ℝ` or `ℂ`, all the conditions follow from the kernel and cokernel having finite +dimension. -/ structure IsFredholm (u : E →L[𝕜] F) : Prop where isStrictMap : IsStrictMap u From 0e5fe7d9a0de93167e9c523aa032ff0601f637f7 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 13:36:04 +0200 Subject: [PATCH 191/210] More --- Mathlib/Analysis/FredholmOperator.lean | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index 2d1800eb525d5c..b679517fadbaa4 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -113,6 +113,19 @@ lemma FredholmPackage.range_eq {u : E →L[𝕜] F} (pkg : FredholmPackage u) : u.range = pkg.dec_codom.X₁ := by simp [pkg.eq_equiv, range_comp] +lemma FredholmPackage.mapsTo {u : E →L[𝕜] F} (pkg : FredholmPackage u) : + MapsTo u pkg.dec_dom.X₁ pkg.dec_codom.X₁ := by + simpa [← FredholmPackage.range_eq, LinearMap.coe_range] using Set.mapsTo_range _ _ + +lemma FredholmPackage.equiv_eq_restrict {u : E →L[𝕜] F} (pkg : FredholmPackage u) : + pkg.equiv = u.restrict pkg.mapsTo := by + ext x + simp [pkg.eq_equiv] + +lemma FredholmPackage.isInvertible_restrict {u : E →L[𝕜] F} (pkg : FredholmPackage u) : + u.restrict pkg.mapsTo |>.IsInvertible := + ⟨pkg.equiv, pkg.equiv_eq_restrict⟩ + /-- The data of a Fredholm package for `u` determines a canonical quasi-inverse of `u`. -/ def FredholmPackage.quasiInverse {u : E →L[𝕜] F} (pkg : FredholmPackage u) : F →L[𝕜] E := @@ -141,6 +154,12 @@ section TFAE end TFAE variable [T2Space E] [T2Space F] in +/-- Assume that `u : E →L[𝕜] F` has a continuous quasi-invers. Then there are closed +subspaces of finite codimensions `E₁` and `F₁` between which `u` induces an isomorphism. + +This statement is private because it is superseded by later results: using `isFredholm_tfae`, +you can build a `FredholmPackage` for `u`, and then apply `FredholmPackage.isInvertible_restrict`. +-/ private theorem exists_restrict_isInvertible_of_isQuasiInverse {u : E →L[𝕜] F} {v : F →L[𝕜] E} (huv : u.IsQuasiInverse v) : ∃ (E₁ : Submodule 𝕜 E) (F₁ : Submodule 𝕜 F), From c4b62732aa3bfba17cfc8650752c8fa14ff6c4d6 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 14:03:17 +0200 Subject: [PATCH 192/210] ++ --- Mathlib/Analysis/FredholmOperator.lean | 48 +++++++++++++++++++++----- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index b679517fadbaa4..acf702e5093232 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -17,8 +17,41 @@ public import Mathlib.Algebra.Module.LinearMap.Index Fix `𝕜` a complete `NontriviallyNormedField`, and `E`, `F` be two Hausdorff topological vector spaces over `𝕜`. -In this file, we define what it means for a continuous linear map `T : E →L[𝕜] F` to be -a **Fredholm operator**. +We say that a continuous linear map `T : E →L[𝕜] F` is a **Fredholm operator** if it satisfies +the following four equivalent conditions: + +1. `T` is strict, its range is closed and has finite codimension, and its kernel is (topologically) + complemented and has finite dimension. This is chosen as the definition, see `IsFredholm`. +2. `T` admits a continuous **quasi-inverse**, in the sense of `LinearMap.IsQuasiInverse`. +3. There are finite-codimension subspaces `E₁` and `F₁` of `E` and `F` between which `T` induces + an isomorphism. +4. `T` admits a `FredholmPackage`: there are topological decompositions `E = E₁ ⊕ E₀`, + `F = F₁ ⊕ F₀`, where `E₀` and `F₀` are finite dimensional, and an isomorphism `Φ : E₁ ≃L[𝕜] F₁` + such that `T` is zero on `E₀` and coincides with `Φ` on `E₁`; in other words, in these + decompositions, `T` is given by the matrix $$\begin{pmatrix} Φ & 0 \cr 0 & 0 \end{pmatrix}$$ + +## Main definitions + +* `ContinuousLinearMap.IsFredholm`: a continuous linear map `u : E →L[𝕜] F` is a + **Fredholm operator** if it is strict, its range is closed and has finite codimension, and its + kernel is (topologically) complemented and has finite dimension. +* `FredholmDecomposition`: a **Fredholm decomposition** of a topological vector space `E` is the + data of two subspaces `X₀` and `X₁` which are topological complements, and where `X₀` is finite + dimensional. +* `ContinuousLinearMap.FredholmPackage`: a **Fredholm package** for `u : E →L[𝕜] F` is the data of + Fredholm decompositions `dec_dom` and `dec_codom` of `E` and `F` respectively, together with + a continuous linear equivalence `equiv : dec_dom.X₁ ≃ₗ[𝕜] dec_codom.X₁` between the "essential" + (i.e finite codimension) parts of these decompositions, such that `u` equals the composition + `dec_codom.X₁.subtypeL ∘L equiv ∘L dec_dom.proj`. + +Note that the data of a `FredholmPackage` for an operator is morally the strongest of the +equivalent ways to assume that `u` is Fredholm (for example, it is clear how to build a canonical +continuous quasi-inverse of `u` from such a package). + +Hence, you should not typically prove that an operator is Fredholm by building a Fredholm package +(consider using `IsFredholm.of_isInvertible_restrict`); instead, when you know that an operator is +Fredholm, you can obtain a `FredholmPackage` from `IsFredholm.nonempty_fredholmPackage` +in order to conveniently use the full strength of Fredholmness. -/ @[expose] public noncomputable section @@ -73,7 +106,7 @@ variable (𝕜 E) in Note that we purposefully use the index `₀` for the "inessential" (i.e finite dimensional) part of the decomposition. -/ -structure FredholmDecomposition where +structure _root_.FredholmDecomposition where X₀ : Submodule 𝕜 E X₁ : Submodule 𝕜 E isTopCompl : IsTopCompl X₁ X₀ @@ -82,19 +115,16 @@ structure FredholmDecomposition where /-- Given a fredhom decomposition `dec` of the space `E`, `dec.proj` is the (continuous linear) projection onto the "essential part" `dec.X₁` along the "inessential part" `dec.X₀`. This is a Fredholm operator. -/ -abbrev FredholmDecomposition.proj (dec : FredholmDecomposition 𝕜 E) : +abbrev _root_.FredholmDecomposition.proj (dec : FredholmDecomposition 𝕜 E) : E →L[𝕜] dec.X₁ := dec.X₁.projectionOntoL dec.X₀ dec.isTopCompl /-- Let `u : E →L[𝕜] F` be a continuous linear map. A **Fredholm package** for `u` is the data of Fredholm decompositions `dec_dom` and `dec_codom` of `E` and `F` respectively, together with a continuous linear equivalence `equiv : dec_dom.X₁ ≃ₗ[𝕜] dec_codom.X₁` between the "essential" (i.e finite codimension) parts of these decompositions, such that `u` equals the composition -`u = dec_codom.X₁.subtypeL ∘L equiv ∘L dec_dom.proj`. In other words, in these +`dec_codom.X₁.subtypeL ∘L equiv ∘L dec_dom.proj`. In other words, in these "essential ⊕ inessential" decompositions, the matrix of `u` is -``` -equiv 0 -0 0 -``` +$$\begin{pmatrix} \texttt{equiv} & 0 \cr 0 & 0 \end{pmatrix}$$ We will show in `isFredholm_tfae` that an operator is Fredholm if and only if it admits a Fredholm package. In practice, the condition that `u` is Fredholm is always easier to From 5cf87b06bfbbf48399cf7c2f4f5a036fbdf9c253 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 14:14:35 +0200 Subject: [PATCH 193/210] Toujours plus --- Mathlib/Analysis/FredholmOperator.lean | 32 ++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index acf702e5093232..0725e7387d1e27 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -52,6 +52,21 @@ Hence, you should not typically prove that an operator is Fredholm by building a (consider using `IsFredholm.of_isInvertible_restrict`); instead, when you know that an operator is Fredholm, you can obtain a `FredholmPackage` from `IsFredholm.nonempty_fredholmPackage` in order to conveniently use the full strength of Fredholmness. + +## Main statements + +* `ContinuousLinearMap.isFredholm_tfae`: the equivalence between conditions 1, 2, 3 and 4 above. + In practice, most of the interesting directions should be covered by specific API lemmas. +* `ContinuousLinearMap.FredholmPackage.isQuasiInverse`: given a `FredholmPackage` for `u`, + one can build a canonical continuous quasi-inverse of `u`. +* `ContinuousLinearMap.IsFredholm.of_isInvertible_restrict`: if a continuous linear map induces + an isomorphism between finite codimension subspaces, then it is Fredholm. +* `ContinuousLinearMap.IsFredholm.of_restrict` (not in Mathlib yet) is a generalization + of the above: if a continuous linear map induces a Fredholm operator between finite codimension + subspaces, then the original map is Fredholm as well. +* `IsFredholm.nonempty_fredholmPackage`: every Fredholm operator admits a Fredholm package. + This is the primary way to obtain Fredholm packages. + -/ @[expose] public noncomputable section @@ -81,8 +96,7 @@ has finite dimension. See also `isFredholm_tfae` for other equivalent characterizations. We will also prove later (not in Mathlib yet) that for maps between Banach (or even Fréchet) spaces over `ℝ` or `ℂ`, all the conditions follow from the kernel and cokernel having finite -dimension. --/ +dimension. -/ structure IsFredholm (u : E →L[𝕜] F) : Prop where isStrictMap : IsStrictMap u isClosed_range : IsClosed (u.range : Set F) @@ -91,6 +105,7 @@ structure IsFredholm (u : E →L[𝕜] F) : Prop where closedComplemented_ker : u.ker.ClosedComplemented variable [CompleteSpace 𝕜] [IsTopologicalAddGroup F] [ContinuousSMul 𝕜 F] in +/-- A Fredholm operator has (topologically) complemented range. -/ lemma IsFredholm.closedComplemented_range {u : E →L[𝕜] F} (u_fred : IsFredholm u) : u.range.ClosedComplemented := have := u_fred.finite_coker @@ -288,6 +303,19 @@ theorem IsFredholm.nonempty_fredholmPackage {u : E →L[𝕜] F} variable [T2Space E] [T2Space F] +/-- +Let `E`, `F` be two Hausdorff topological vector spaces over a complete `NontriviallyNormedField` +denoted `𝕜`, and `u : E →L[𝕜] F` a continuous linear map. The followng conditions are equivalent: + +1. `T` is a **Fredholm operator**, in the sense of `ContinuousLinearMap.IsFredholm`. +2. `T` admits a continuous **quasi-inverse**, in the sense of `LinearMap.IsQuasiInverse`. +3. There are finite-codimension subspaces `E₁` and `F₁` of `E` and `F` between which `T` induces + an isomorphism. +4. `T` admits a `FredholmPackage`. + +In practice, condition `4` is the "strongest", so you should probably not use it to *prove* that an +operator is Fredholm. +-/ theorem isFredholm_tfae (u : E →L[𝕜] F) : List.TFAE [ IsFredholm u, From fa035edca968af62128a1ffe8699e79a5d720912 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 14:28:49 +0200 Subject: [PATCH 194/210] Documentation done ! --- Mathlib/Analysis/FredholmOperator.lean | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index 0725e7387d1e27..9e9f62d7969e2c 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -55,6 +55,8 @@ in order to conveniently use the full strength of Fredholmness. ## Main statements +### Equivalent criterions + * `ContinuousLinearMap.isFredholm_tfae`: the equivalence between conditions 1, 2, 3 and 4 above. In practice, most of the interesting directions should be covered by specific API lemmas. * `ContinuousLinearMap.FredholmPackage.isQuasiInverse`: given a `FredholmPackage` for `u`, @@ -67,6 +69,29 @@ in order to conveniently use the full strength of Fredholmness. * `IsFredholm.nonempty_fredholmPackage`: every Fredholm operator admits a Fredholm package. This is the primary way to obtain Fredholm packages. +## Implementation details + +We largely follow [N. Bourbaki, *Théories Spectrales*, Chapitre III, § 3, n° 2][bourbaki2023], +in particular for the proof of equivalence of the four conditions above. +Here are some notable changes : + +* Bourbaki restricts itself to locally convex spaces over `ℝ` or `ℂ`. Yet, under close inspection, + this assumption plays very little role in the theory. In fact, at the very mild cost of assuming + that the kernel is complemented in the definition of `IsFredholm` (which follows from the + finiteness of its dimension if Hahn-Banach is available), we generalize the beginning of the + theory to topological vector spaces over any complete nontrivially normed field. In particular, + our theory naturally captures p-adic Fredholm operators. +* Bourbaki choses the existence of a continuous quasi-inverse as the definition of being Fredholm. + Our choice differs for a very practical reason: it is much simpler to spell out formally + "`u` has a continuous quasi-inverse" than "`u` is strict, its range is closed and has finite + codimension, and its kernel is complemented and has finite dimension". Hence we prefer to give + a name to the latter. + + +## References + +* [N. Bourbaki, *Théories Spectrales*, Chapitre III, § 3, n° 2][bourbaki2023] + -/ @[expose] public noncomputable section @@ -338,6 +363,7 @@ theorem isFredholm_tfae (u : E →L[𝕜] F) : List.TFAE exact .of_isInvertible_restrict E₁_closed F₁_closed u_mapsto u_invertible tfae_finish +/-- If `u` has a Fredholm package, it is Fredholm. -/ theorem FredholmPackage.isFredholm {u : E →L[𝕜] F} (pkg : FredholmPackage u) : IsFredholm u := isFredholm_tfae u |>.out 3 0 |>.mp (Nonempty.intro pkg) From ad63166791758e4e2a035314a193eadb23334ea6 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 14:40:32 +0200 Subject: [PATCH 195/210] more honest --- Mathlib/Analysis/FredholmOperator.lean | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index 9e9f62d7969e2c..552f890a105ced 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -76,9 +76,9 @@ in particular for the proof of equivalence of the four conditions above. Here are some notable changes : * Bourbaki restricts itself to locally convex spaces over `ℝ` or `ℂ`. Yet, under close inspection, - this assumption plays very little role in the theory. In fact, at the very mild cost of assuming - that the kernel is complemented in the definition of `IsFredholm` (which follows from the - finiteness of its dimension if Hahn-Banach is available), we generalize the beginning of the + this assumption plays very little role in the beginning of the theory. In fact, at the very mild + cost of assuming that the kernel is complemented in the definition of `IsFredholm` (which follows + from the finiteness assumption if Hahn-Banach is available), we generalize the beginning of the theory to topological vector spaces over any complete nontrivially normed field. In particular, our theory naturally captures p-adic Fredholm operators. * Bourbaki choses the existence of a continuous quasi-inverse as the definition of being Fredholm. From b90eaaf8375bb6cf30813460eb96bbeff431df53 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 14:50:57 +0200 Subject: [PATCH 196/210] remove not fully satisfying statement --- Mathlib/LinearAlgebra/Span/Basic.lean | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Mathlib/LinearAlgebra/Span/Basic.lean b/Mathlib/LinearAlgebra/Span/Basic.lean index b2319a5241708c..cd957fe7a6343d 100644 --- a/Mathlib/LinearAlgebra/Span/Basic.lean +++ b/Mathlib/LinearAlgebra/Span/Basic.lean @@ -643,20 +643,6 @@ variable [AddCommGroup M] [Module R M] [AddCommGroup M₂] [Module R₂ M₂] variable {τ₁₂ : R →+* R₂} [RingHomSurjective τ₁₂] variable {p p' : Submodule R M} -/-- Let `f : M →ₗ N`. Assume that `p` and `q` are disjoint submodules of `M`, -and that the kernel of `f` "decomposes well" wrt. `p` and `q`, in the sense that -`f.ker = (f.ker ⊓ p) ⊔ (f.ker ⊓ q)`. Then `map f p` and `map f q` are disjoint. -/ -lemma disjoint_map_of_ker_le_inf_sup {f : M →ₛₗ[τ₁₂] M₂} {p q : Submodule R M} - (hpq : Disjoint p q) (hker : f.ker ≤ (f.ker ⊓ p) ⊔ (f.ker ⊓ q)) : - Disjoint (p.map f) (q.map f) := by - replace hker : f.ker = (f.ker ⊓ p) ⊔ (f.ker ⊓ q) := - le_antisymm hker (sup_le inf_le_left inf_le_left) - have : q ⊔ f.ker = q ⊔ (p ⊓ f.ker) := by - conv_lhs => rw [hker, inf_comm]; simp only [← sup_assoc, inf_left_le_sup_right, sup_of_le_left] - rw [disjoint_iff, map_inf_eq_map_inf_comap, comap_map_eq, eq_bot_iff, map_le_iff_le_comap, - comap_bot, this, ← inf_sup_assoc_of_le _ inf_le_left, hpq.eq_bot, bot_sup_eq] - exact inf_le_right - theorem map_strict_mono_or_ker_sup_lt_ker_sup (f : M →ₛₗ[τ₁₂] M₂) (hab : p < p') : Submodule.map f p < Submodule.map f p' ∨ LinearMap.ker f ⊓ p < LinearMap.ker f ⊓ p' := by obtain (⟨h, -⟩ | ⟨-, h⟩) := Prod.mk_lt_mk.mp <| strictMono_inf_prod_sup (z := LinearMap.ker f) hab From bf8e93aaa3c7af6df293b99acdca30a98a2b5b27 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 15:16:33 +0200 Subject: [PATCH 197/210] variable --- Mathlib/Topology/Maps/Strict/Basic.lean | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index 2bf2540a33018e..929fa71bcae94e 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -43,15 +43,14 @@ open Function Set Topology Setoid namespace Topology variable {X Y Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] - (f : X → Y) {g : Y → Z} + {f : X → Y} {g : Y → Z} +variable (f) in /-- A map is a strict map in the sense of Bourbaki if the natural map to its image is a quotient map. -/ def IsStrictMap : Prop := IsQuotientMap (Set.rangeFactorization f) -variable {f} - lemma isStrictMap_iff_isQuotientMap_rangeFactorization : IsStrictMap f ↔ IsQuotientMap (Set.rangeFactorization f) := Iff.rfl From adb65aac95851af38083b5cab5a95aabc71f5e2f Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 15:20:30 +0200 Subject: [PATCH 198/210] Deprecations --- Mathlib/Topology/Maps/Strict/Basic.lean | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Mathlib/Topology/Maps/Strict/Basic.lean b/Mathlib/Topology/Maps/Strict/Basic.lean index 929fa71bcae94e..8489dffef5bae0 100644 --- a/Mathlib/Topology/Maps/Strict/Basic.lean +++ b/Mathlib/Topology/Maps/Strict/Basic.lean @@ -70,6 +70,9 @@ noncomputable def _root_.Homeomorph.quotientKerEquivRange (hf : IsStrictMap f) : Quotient (Setoid.ker f) ≃ₜ Set.range f := (isStrictMap_iff_isHomeomorph_quotientKerEquivRange.mp hf).homeomorph +@[deprecated (since := "2026-07-10")] protected alias Homeomorph.quotientKerEquivRange := + Homeomorph.quotientKerEquivRange + /-- A map is a strict map if and only if the canonical injection `Quotient (Setoid.ker f) → Y` (`Setoid.kerLift f`) is an embedding. -/ theorem isStrictMap_iff_isEmbedding_kerLift : @@ -90,6 +93,9 @@ lemma _root_.IsOpenMap.isStrictMap (ho : IsOpenMap f) (h_cont : Continuous f) : exact (ho.subtype_mk fun x => ⟨x, rfl⟩).isQuotientMap h_cont.rangeFactorization Set.rangeFactorization_surjective +@[deprecated (since := "2026-07-10")] protected alias IsOpenMap.isStrictMap := + IsOpenMap.isStrictMap + /-- A closed continuous map is a strict map. -/ lemma _root_.IsClosedMap.isStrictMap (hc : IsClosedMap f) (h_cont : Continuous f) : IsStrictMap f := by @@ -97,11 +103,17 @@ lemma _root_.IsClosedMap.isStrictMap (hc : IsClosedMap f) (h_cont : Continuous f exact (hc.subtype_mk fun x => ⟨x, rfl⟩).isQuotientMap h_cont.rangeFactorization Set.rangeFactorization_surjective +@[deprecated (since := "2026-07-10")] protected alias IsClosedMap.isStrictMap := + IsClosedMap.isStrictMap + /-- A homeomorphism is a strict map. -/ lemma _root_.IsHomeomorph.isStrictMap (f_homeo : IsHomeomorph f) : IsStrictMap f := f_homeo.isOpenMap.isStrictMap f_homeo.continuous +@[deprecated (since := "2026-07-10")] protected alias IsHomeomorph.isStrictMap := + IsHomeomorph.isStrictMap + /-- The identity is a strict map. -/ lemma IsStrictMap.id : IsStrictMap (id : X → X) := IsHomeomorph.id.isStrictMap @@ -164,9 +176,15 @@ lemma _root_.Homeomorph.isStrictMap_comp_iff (e : X ≃ₜ Y) {f : Y → Z} : IsStrictMap (f ∘ e) ↔ IsStrictMap f := e.isQuotientMap.isStrictMap_iff.symm +@[deprecated (since := "2026-07-10")] protected alias Homeomorph.isStrictMap_comp_iff := + Homeomorph.isStrictMap_comp_iff + /-- Strict maps are preserved when postcomposing with a homeomorphism. -/ lemma _root_.Homeomorph.comp_isStrictMap_iff (e : Y ≃ₜ Z) {f : X → Y} : IsStrictMap (e ∘ f) ↔ IsStrictMap f := e.isEmbedding.isStrictMap_iff.symm +@[deprecated (since := "2026-07-10")] protected alias Homeomorph.comp_isStrictMap_iff := + Homeomorph.comp_isStrictMap_iff + end Topology From b86390b65b90e9a9eac30f690d616335bd2cb6a2 Mon Sep 17 00:00:00 2001 From: Anatole Dedecker Date: Fri, 10 Jul 2026 15:27:39 +0200 Subject: [PATCH 199/210] Update Mathlib/Topology/Maps/Strict/Group.lean Co-authored-by: Monica Omar <23701951+themathqueen@users.noreply.github.com> --- Mathlib/Topology/Maps/Strict/Group.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Topology/Maps/Strict/Group.lean b/Mathlib/Topology/Maps/Strict/Group.lean index d8ea8634f26d66..b1835b4dcc0135 100644 --- a/Mathlib/Topology/Maps/Strict/Group.lean +++ b/Mathlib/Topology/Maps/Strict/Group.lean @@ -100,6 +100,6 @@ protected lemma isStrictMap_prodMap (hf : IsStrictMap f) (hg : IsStrictMap g) : IsStrictMap (f.prodMap g) := MonoidHom.isStrictMap_prodMap_iff.mpr ⟨hf, hg⟩ --- TODO Add the lemma `isStrictMap_piMap` once `MonoidHom.piMap` has been defined. +-- TODO: Add the lemma `isStrictMap_piMap` once `MonoidHom.piMap` has been defined. end MonoidHom From b471c213798b828c037471c96e28697458e9da10 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 17:47:43 +0200 Subject: [PATCH 200/210] Alphabetical order --- Mathlib/Analysis/FredholmOperator.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index 552f890a105ced..8ee3beb73a782d 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2026 Filippo A. E. Nuccio. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Jon Bannon, Anatole Dedecker, Patrick Massot, Yongxi Lin, Oliver Nash, Filippo A. E. Nuccio +Authors: Jon Bannon, Anatole Dedecker, Yongxi Lin, Patrick Massot, Oliver Nash, Filippo A. E. Nuccio -/ module From 3ff0e2a03052677b87e9cea6f2ae09e71dbd954d Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 18:21:21 +0200 Subject: [PATCH 201/210] More implicit --- Mathlib/Topology/Maps/Strict/Group.lean | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Mathlib/Topology/Maps/Strict/Group.lean b/Mathlib/Topology/Maps/Strict/Group.lean index b1835b4dcc0135..f199f927ff1b1e 100644 --- a/Mathlib/Topology/Maps/Strict/Group.lean +++ b/Mathlib/Topology/Maps/Strict/Group.lean @@ -33,7 +33,7 @@ open Function Set Topology QuotientGroup namespace MonoidHom -variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] (f : G →* H) (g : G' →* H') +variable {G H G' H' : Type*} [Group G'] [Group H'] [Group G] [Group H] {f : G →* H} {g : G' →* H'} [TopologicalSpace G] [TopologicalSpace H] /-- A group homomorphism is strict if and only if its `QuotientGroup.kerLift` is an embedding. -/ @@ -59,7 +59,6 @@ protected lemma isStrictMap_iff_isHomeomorph_quotientKerEquivRange : (isQuotientMap_mk _).isStrictMap_iff, IsEmbedding.subtypeVal.isStrictMap_iff] rfl -variable {f} in /-- The isomorphism of topological groups `G ⧸ f.ker ≃ f.range` given by a strict group homomorphism `f`. This is an avatar of the first isomorphism theorem. -/ @[to_additive /-- The isomorphism of topological additive groups `G ⧸ f.ker ≃ f.range` given by a @@ -79,7 +78,7 @@ protected lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict : rw [isOpenQuotientMap_iff_isQuotientMap] rfl -variable {f g} [TopologicalSpace G'] [IsTopologicalGroup G'] [TopologicalSpace H'] +variable [TopologicalSpace G'] [IsTopologicalGroup G'] [TopologicalSpace H'] /-- The product (in the sense of `Prod.map`) of group homomorphisms is strict if and only if each of the homomorphisms is strict. -/ From 07671d02575ec2ed5136ad956ab26c21f2f63086 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 18:27:01 +0200 Subject: [PATCH 202/210] all implicit --- Mathlib/Topology/Maps/Strict/Module.lean | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Mathlib/Topology/Maps/Strict/Module.lean b/Mathlib/Topology/Maps/Strict/Module.lean index ebce43ec67c655..0aafbd88f734d8 100644 --- a/Mathlib/Topology/Maps/Strict/Module.lean +++ b/Mathlib/Topology/Maps/Strict/Module.lean @@ -29,7 +29,7 @@ namespace LinearMap variable {R S M N Nₗ M' Nₗ' : Type*} [Ring R] [Ring S] {σ : R →+* S} [AddCommGroup M] [AddCommGroup N] [AddCommGroup Nₗ] [AddCommGroup M'] [AddCommGroup Nₗ'] [Module R M] [Module S N] [Module R Nₗ] [Module R M'] [Module R Nₗ'] - (f : M →ₛₗ[σ] N) (fₗ : M →ₗ[R] Nₗ) (gₗ : M' →ₗ[R] Nₗ') + {f : M →ₛₗ[σ] N} {fₗ : M →ₗ[R] Nₗ} {gₗ : M' →ₗ[R] Nₗ'} [TopologicalSpace M] [TopologicalSpace N] [TopologicalSpace Nₗ] /-- A linear map `f : E → F` is strict if and only the induced map `E ⧸ f.ker → F` is an @@ -46,7 +46,6 @@ protected lemma isStrictMap_iff_isHomeomorph_quotKerEquivRange : fₗ.ker.isQuotientMap_mkQ.isStrictMap_iff, IsEmbedding.subtypeVal.isStrictMap_iff] rfl -variable {f} in /-- The isomorphism of topological modules `E ⧸ f.ker ≃ f.range` given by a strict linear map `f : E → F`. This is an avatar of the first isomorphism theorem. -/ noncomputable def _root_.ContinuousLinearEquiv.quotKerEquivRange @@ -60,7 +59,7 @@ protected lemma isStrictMap_iff_isOpenQuotientMap_rangeRestrict [RingHomSurjecti IsStrictMap f ↔ IsOpenQuotientMap f.rangeRestrict := f.toAddMonoidHom.isStrictMap_iff_isOpenQuotientMap_rangeRestrict -variable {f fₗ gₗ} [TopologicalSpace M'] [IsTopologicalAddGroup M'] [TopologicalSpace Nₗ'] +variable [TopologicalSpace M'] [IsTopologicalAddGroup M'] [TopologicalSpace Nₗ'] /-- The product (in the sense of `LinearMap.prodMap`) of linear maps is strict if and only if each of the maps is strict. -/ From c6a544127ab5730fb27cafd8a1fd8f928930e393 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 18:27:22 +0200 Subject: [PATCH 203/210] -- --- Mathlib/Topology/Maps/Strict/Module.lean | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Mathlib/Topology/Maps/Strict/Module.lean b/Mathlib/Topology/Maps/Strict/Module.lean index 0aafbd88f734d8..d977ac68bfb395 100644 --- a/Mathlib/Topology/Maps/Strict/Module.lean +++ b/Mathlib/Topology/Maps/Strict/Module.lean @@ -15,8 +15,7 @@ public import Mathlib.Topology.Maps.Strict.Group In this file, we study continuous linear maps which are *strict* in the sense of `Topology.IsStrictMap`. So far, all the results in this file are direct -adaptations from the theory of strict homomorphisms of topological additive groups, -but this may change in the future. +adaptations from the theory of strict homomorphisms of topological additive groups. -/ From 2efb334d6342043bd171818a511c4dc174e5f27a Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 18:30:35 +0200 Subject: [PATCH 204/210] fix --- Mathlib/Analysis/FredholmOperator.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index 8ee3beb73a782d..db36bfa285a898 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -306,7 +306,7 @@ def IsFredholm.fredholmPackage {u : E →L[𝕜] F} finite_X₀ := .of_fg <| u_fred.finite_coker.fg_of_isCompl h_codom.isCompl } equiv := letI Φ : dom₁ ≃L[𝕜] E ⧸ u.ker := u.ker.quotientEquivOfIsTopCompl dom₁ h_dom |>.symm - letI Ψ : (E ⧸ u.ker) ≃L[𝕜] u.range := .quotKerEquivRange u.toLinearMap u_fred.isStrictMap + letI Ψ : (E ⧸ u.ker) ≃L[𝕜] u.range := .quotKerEquivRange u_fred.isStrictMap Φ.trans Ψ eq_equiv := by refine LinearMap.ext_on_codisjoint h_dom.isCompl.codisjoint ?_ ?_ From ebd54e8a5f079b72bf8f823ade4b3fc55c0b369b Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 18:48:15 +0200 Subject: [PATCH 205/210] feat: composition of Fredholm operators --- Mathlib/Analysis/FredholmOperator.lean | 35 ++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index db36bfa285a898..060dec17360ac3 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -103,8 +103,10 @@ open LinearMap.FiniteRangeSetoid section TVS namespace ContinuousLinearMap -variable {𝕜 E F : Type*} [NontriviallyNormedField 𝕜] [AddCommGroup E] [AddCommGroup F] - [Module 𝕜 E] [Module 𝕜 F] [TopologicalSpace E] [TopologicalSpace F] +variable {𝕜 E F G : Type*} [NontriviallyNormedField 𝕜] + [AddCommGroup E] [AddCommGroup F] [AddCommGroup G] + [Module 𝕜 E] [Module 𝕜 F] [Module 𝕜 G] + [TopologicalSpace E] [TopologicalSpace F] [TopologicalSpace G] /-! ## Definition and equivalent conditions @@ -368,8 +370,37 @@ theorem FredholmPackage.isFredholm {u : E →L[𝕜] F} (pkg : FredholmPackage u IsFredholm u := isFredholm_tfae u |>.out 3 0 |>.mp (Nonempty.intro pkg) +theorem isFredholm_iff_exists_isQuasiInverse {u : E →L[𝕜] F} : + IsFredholm u ↔ ∃ v : F →L[𝕜] E, u.IsQuasiInverse v := + isFredholm_tfae u |>.out 0 1 + end DefTFAE +section Constructions + +variable [CompleteSpace 𝕜] [IsTopologicalAddGroup E] [IsTopologicalAddGroup F] + [IsTopologicalAddGroup G] [ContinuousSMul 𝕜 E] [ContinuousSMul 𝕜 F] [ContinuousSMul 𝕜 G] + [T2Space E] [T2Space F] [T2Space G] + +theorem isFredholm_congr {u u' : E →L[𝕜] F} (h : u.toLinearMap ≈ u'.toLinearMap) : + IsFredholm u ↔ IsFredholm u' := by + simp_rw [isFredholm_iff_exists_isQuasiInverse] + refine exists_congr fun _ ↦ isQuasiInverse_congr (Setoid.symm h) (Setoid.refl _) + +theorem IsFredholm.congr {u u' : E →L[𝕜] F} (hu : IsFredholm u) + (h : u.toLinearMap ≈ u'.toLinearMap) : + IsFredholm u' := by + rwa [← isFredholm_congr h] + +theorem IsFredholm.comp {f : E →L[𝕜] F} {f' : F →L[𝕜] G} (hf : IsFredholm f) + (hf' : IsFredholm f') : IsFredholm (f' ∘L f) := by + rw [isFredholm_iff_exists_isQuasiInverse] at * + rcases hf with ⟨g, hg⟩ + rcases hf' with ⟨g', hg'⟩ + exact ⟨g ∘L g', hg'.comp hg⟩ + +end Constructions + end ContinuousLinearMap end TVS From 0ea65afb35e88081462da167aca600394d8b200c Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 19:15:43 +0200 Subject: [PATCH 206/210] field docs --- Mathlib/Analysis/FredholmOperator.lean | 45 ++++++++++++++------------ 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index db36bfa285a898..cb9e11a2479370 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -39,10 +39,10 @@ the following four equivalent conditions: data of two subspaces `X₀` and `X₁` which are topological complements, and where `X₀` is finite dimensional. * `ContinuousLinearMap.FredholmPackage`: a **Fredholm package** for `u : E →L[𝕜] F` is the data of - Fredholm decompositions `dec_dom` and `dec_codom` of `E` and `F` respectively, together with - a continuous linear equivalence `equiv : dec_dom.X₁ ≃ₗ[𝕜] dec_codom.X₁` between the "essential" + Fredholm decompositions `decDom` and `decCodom` of `E` and `F` respectively, together with + a continuous linear equivalence `equiv : decDom.X₁ ≃ₗ[𝕜] decCodom.X₁` between the "essential" (i.e finite codimension) parts of these decompositions, such that `u` equals the composition - `dec_codom.X₁.subtypeL ∘L equiv ∘L dec_dom.proj`. + `decCodom.X₁.subtypeL ∘L equiv ∘L decDom.proj`. Note that the data of a `FredholmPackage` for an operator is morally the strongest of the equivalent ways to assume that `u` is Fredholm (for example, it is clear how to build a canonical @@ -147,7 +147,9 @@ variable (𝕜 E) in Note that we purposefully use the index `₀` for the "inessential" (i.e finite dimensional) part of the decomposition. -/ structure _root_.FredholmDecomposition where + /-- The inessential (i.e finite dimensional) part of a Fredholm decomposition. -/ X₀ : Submodule 𝕜 E + /-- The essential (i.e finite co-dimensional) part of a Fredholm decomposition. -/ X₁ : Submodule 𝕜 E isTopCompl : IsTopCompl X₁ X₀ finite_X₀ : FiniteDimensional 𝕜 X₀ @@ -159,10 +161,10 @@ abbrev _root_.FredholmDecomposition.proj (dec : FredholmDecomposition 𝕜 E) : E →L[𝕜] dec.X₁ := dec.X₁.projectionOntoL dec.X₀ dec.isTopCompl /-- Let `u : E →L[𝕜] F` be a continuous linear map. A **Fredholm package** for `u` is the data of -Fredholm decompositions `dec_dom` and `dec_codom` of `E` and `F` respectively, together with -a continuous linear equivalence `equiv : dec_dom.X₁ ≃ₗ[𝕜] dec_codom.X₁` between the "essential" +Fredholm decompositions `decDom` and `decCodom` of `E` and `F` respectively, together with +a continuous linear equivalence `equiv : decDom.X₁ ≃ₗ[𝕜] decCodom.X₁` between the "essential" (i.e finite codimension) parts of these decompositions, such that `u` equals the composition -`dec_codom.X₁.subtypeL ∘L equiv ∘L dec_dom.proj`. In other words, in these +`decCodom.X₁.subtypeL ∘L equiv ∘L decDom.proj`. In other words, in these "essential ⊕ inessential" decompositions, the matrix of `u` is $$\begin{pmatrix} \texttt{equiv} & 0 \cr 0 & 0 \end{pmatrix}$$ @@ -171,20 +173,23 @@ a Fredholm package. In practice, the condition that `u` is Fredholm is always ea prove, so if you need a Fredholm package you should probably get it from `IsFredholm.nonempty_fredholmPackage` or `IsFredholm.fredholmPackage`. -/ structure FredholmPackage (u : E →L[𝕜] F) where - dec_dom : FredholmDecomposition 𝕜 E - dec_codom : FredholmDecomposition 𝕜 F - equiv : dec_dom.X₁ ≃L[𝕜] dec_codom.X₁ - eq_equiv : u = dec_codom.X₁.subtypeL ∘L equiv ∘L dec_dom.proj + /-- A `FredholmDecomposition` of the domain. -/ + decDom : FredholmDecomposition 𝕜 E + /-- A `FredholmDecomposition` of the codomain. -/ + decCodom : FredholmDecomposition 𝕜 F + /-- An isomorphism between the essential parts of `decDom` and `decCodom`. -/ + equiv : decDom.X₁ ≃L[𝕜] decCodom.X₁ + eq_equiv : u = decCodom.X₁.subtypeL ∘L equiv ∘L decDom.proj lemma FredholmPackage.ker_eq {u : E →L[𝕜] F} (pkg : FredholmPackage u) : - u.ker = pkg.dec_dom.X₀ := by simp [pkg.eq_equiv, ker_comp] + u.ker = pkg.decDom.X₀ := by simp [pkg.eq_equiv, ker_comp] lemma FredholmPackage.range_eq {u : E →L[𝕜] F} (pkg : FredholmPackage u) : - u.range = pkg.dec_codom.X₁ := by + u.range = pkg.decCodom.X₁ := by simp [pkg.eq_equiv, range_comp] lemma FredholmPackage.mapsTo {u : E →L[𝕜] F} (pkg : FredholmPackage u) : - MapsTo u pkg.dec_dom.X₁ pkg.dec_codom.X₁ := by + MapsTo u pkg.decDom.X₁ pkg.decCodom.X₁ := by simpa [← FredholmPackage.range_eq, LinearMap.coe_range] using Set.mapsTo_range _ _ lemma FredholmPackage.equiv_eq_restrict {u : E →L[𝕜] F} (pkg : FredholmPackage u) : @@ -199,17 +204,17 @@ lemma FredholmPackage.isInvertible_restrict {u : E →L[𝕜] F} (pkg : Fredholm /-- The data of a Fredholm package for `u` determines a canonical quasi-inverse of `u`. -/ def FredholmPackage.quasiInverse {u : E →L[𝕜] F} (pkg : FredholmPackage u) : F →L[𝕜] E := - pkg.dec_dom.X₁.subtypeL ∘L pkg.equiv.symm ∘L pkg.dec_codom.proj + pkg.decDom.X₁.subtypeL ∘L pkg.equiv.symm ∘L pkg.decCodom.proj /-- The data of a Fredholm package for `u` determines a canonical quasi-inverse of `u`. -/ lemma FredholmPackage.isQuasiInverse {u : E →L[𝕜] F} (pkg : FredholmPackage u) : u.IsQuasiInverse pkg.quasiInverse := by nth_rw 1 [pkg.eq_equiv, quasiInverse] - have hdom : IsQuasiInverse pkg.dec_dom.X₁.subtype pkg.dec_dom.proj := - have := pkg.dec_dom.finite_X₀ + have hdom : IsQuasiInverse pkg.decDom.X₁.subtype pkg.decDom.proj := + have := pkg.decDom.finite_X₀ isQuasiInverse_subtype_projectionOnto _ - have hcodom : IsQuasiInverse pkg.dec_codom.X₁.subtype pkg.dec_codom.proj := - have := pkg.dec_codom.finite_X₀ + have hcodom : IsQuasiInverse pkg.decCodom.X₁.subtype pkg.decCodom.proj := + have := pkg.decCodom.finite_X₀ isQuasiInverse_subtype_projectionOnto _ refine .of_comp_left hcodom.symm <| .of_comp_right hdom ?_ simp_rw [FredholmDecomposition.proj, toLinearMap_comp, toLinearMap_subtypeL, @@ -294,12 +299,12 @@ def IsFredholm.fredholmPackage {u : E →L[𝕜] F} (u_fred : IsFredholm u) {dom₁ : Submodule 𝕜 E} {codom₀ : Submodule 𝕜 F} (h_dom : IsTopCompl u.ker dom₁) (h_codom : IsTopCompl u.range codom₀) : FredholmPackage u where - dec_dom := { + decDom := { X₀ := u.ker X₁ := dom₁ isTopCompl := h_dom.symm finite_X₀ := u_fred.finite_ker } - dec_codom := { + decCodom := { X₀ := codom₀ X₁ := u.range isTopCompl := h_codom From 3536646715cc98104ebb50b5ad942c992f58649e Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 21:26:36 +0200 Subject: [PATCH 207/210] composition cancelling and identity --- Mathlib/Analysis/FredholmOperator.lean | 28 ++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index fde4695429d0d6..e795472591e3ef 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -397,13 +397,37 @@ theorem IsFredholm.congr {u u' : E →L[𝕜] F} (hu : IsFredholm u) IsFredholm u' := by rwa [← isFredholm_congr h] -theorem IsFredholm.comp {f : E →L[𝕜] F} {f' : F →L[𝕜] G} (hf : IsFredholm f) - (hf' : IsFredholm f') : IsFredholm (f' ∘L f) := by +theorem IsFredholm.comp {f' : F →L[𝕜] G} {f : E →L[𝕜] F} (hf' : IsFredholm f') + (hf : IsFredholm f) : IsFredholm (f' ∘L f) := by rw [isFredholm_iff_exists_isQuasiInverse] at * rcases hf with ⟨g, hg⟩ rcases hf' with ⟨g', hg'⟩ exact ⟨g ∘L g', hg'.comp hg⟩ +theorem IsFredholm.comp_iff_left {f : E →L[𝕜] F} {f' : F →L[𝕜] G} (hf : IsFredholm f) : + IsFredholm (f' ∘L f) ↔ IsFredholm f' := by + refine ⟨fun hcomp ↦ ?_, fun hf' ↦ hf'.comp hf⟩ + rw [isFredholm_iff_exists_isQuasiInverse, toLinearMap_comp] at * + rcases hf with ⟨g, hg⟩ + rcases hcomp with ⟨w, hw⟩ + exact ⟨f ∘L w, .symm <| hg.symm.of_comp_left hw.symm⟩ + +theorem IsFredholm.comp_iff_right {f : E →L[𝕜] F} {f' : F →L[𝕜] G} (hf' : IsFredholm f') : + IsFredholm (f' ∘L f) ↔ IsFredholm f := by + refine ⟨fun hcomp ↦ ?_, fun hf ↦ hf'.comp hf⟩ + rw [isFredholm_iff_exists_isQuasiInverse, toLinearMap_comp] at * + rcases hf' with ⟨g', hg'⟩ + rcases hcomp with ⟨w, hw⟩ + exact ⟨w ∘L f', .symm <| hg'.symm.of_comp_right hw.symm⟩ + +theorem _root_.ContinuousLinearEquiv.isFredholm (e : E ≃L[𝕜] F) : + IsFredholm (e : E →L[𝕜] F) := + isFredholm_iff_exists_isQuasiInverse.mpr + ⟨e.symm, by simp [IsQuasiInverse, IsLeftQuasiInverse, IsRightQuasiInverse]⟩ + +theorem IsFredholm.id : IsFredholm (.id 𝕜 E) := + ContinuousLinearEquiv.refl 𝕜 E |>.isFredholm + end Constructions end ContinuousLinearMap From 6e4b3a5f98c204b10ee2ee44402f45c112dfb533 Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 21:50:59 +0200 Subject: [PATCH 208/210] feat: constructions of Fredholm operators --- Mathlib/Analysis/FredholmOperator.lean | 57 ++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index e795472591e3ef..2a89d696ac0047 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -383,6 +383,55 @@ end DefTFAE section Constructions +theorem _root_.ContinuousLinearEquiv.isFredholm (e : E ≃L[𝕜] F) : + IsFredholm (e : E →L[𝕜] F) where + isStrictMap := e.isHomeomorph.isStrictMap + isClosed_range := by simp + finite_ker := by --show FiniteDimensional 𝕜 e.toLinearEquiv.toLinearMap.ker by + rw [LinearMap.ker_eq_bot.2 (by exact EquivLike.injective e)] + infer_instance + finite_coker := by simp + closedComplemented_ker := by simp + +theorem IsFredholm.id : IsFredholm (.id 𝕜 E) := + ContinuousLinearEquiv.refl 𝕜 E |>.isFredholm + +theorem _root_.Topology.IsClosedEmbedding.isFredholmStruct {f : E →L[𝕜] F} + (hf : IsClosedEmbedding f) (hcofg : f.range.CoFG) : + IsFredholm f where + isStrictMap := hf.isStrictMap + isClosed_range := hf.isClosed_range + finite_ker := by + rw [LinearMap.ker_eq_bot.2 hf.injective] + infer_instance + finite_coker := by simp [hcofg] + closedComplemented_ker := by + rw [LinearMap.ker_eq_bot.2 hf.injective] + exact closedComplemented_bot + +theorem _root_.Submodule.isFredholm_subtypeL {p : Submodule 𝕜 E} + (hp : IsClosed (p : Set E)) (hc : p.CoFG) : + IsFredholm p.subtypeL := + (IsClosedEmbedding.subtypeVal hp).isFredholmStruct (by simpa) + +theorem _root_.Topology.IsQuotientMap.isFredholm {f : E →L[𝕜] F} (hq : IsQuotientMap f) + (hfg : FiniteDimensional 𝕜 f.ker) (hcompl : f.ker.ClosedComplemented) : + IsFredholm f where + isStrictMap := hq.isStrictMap + isClosed_range := by + rw [LinearMap.range_eq_top.2 hq.surjective] + exact isClosed_univ + finite_ker := hfg + finite_coker := by + rw [LinearMap.range_eq_top.2 hq.surjective] + exact Submodule.CoFG.top + closedComplemented_ker := hcompl + +theorem _root_.Submodule.mkQL_isFredholmStruct {p : Submodule 𝕜 E} (hc : FiniteDimensional 𝕜 p) + (hcompl : p.ClosedComplemented) : + IsFredholm p.mkQL := + p.isQuotientMap_mkQL.isFredholm (by rwa [toLinearMap_mkQL, ker_mkQ]) (by simpa) + variable [CompleteSpace 𝕜] [IsTopologicalAddGroup E] [IsTopologicalAddGroup F] [IsTopologicalAddGroup G] [ContinuousSMul 𝕜 E] [ContinuousSMul 𝕜 F] [ContinuousSMul 𝕜 G] [T2Space E] [T2Space F] [T2Space G] @@ -420,14 +469,6 @@ theorem IsFredholm.comp_iff_right {f : E →L[𝕜] F} {f' : F →L[𝕜] G} (hf rcases hcomp with ⟨w, hw⟩ exact ⟨w ∘L f', .symm <| hg'.symm.of_comp_right hw.symm⟩ -theorem _root_.ContinuousLinearEquiv.isFredholm (e : E ≃L[𝕜] F) : - IsFredholm (e : E →L[𝕜] F) := - isFredholm_iff_exists_isQuasiInverse.mpr - ⟨e.symm, by simp [IsQuasiInverse, IsLeftQuasiInverse, IsRightQuasiInverse]⟩ - -theorem IsFredholm.id : IsFredholm (.id 𝕜 E) := - ContinuousLinearEquiv.refl 𝕜 E |>.isFredholm - end Constructions end ContinuousLinearMap From ad5ad776fc13f51fd210e05e8cc98c8785dd966a Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 21:54:37 +0200 Subject: [PATCH 209/210] ++ --- Mathlib/Analysis/FredholmOperator.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index 2a89d696ac0047..430f8525f16e1f 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -387,8 +387,8 @@ theorem _root_.ContinuousLinearEquiv.isFredholm (e : E ≃L[𝕜] F) : IsFredholm (e : E →L[𝕜] F) where isStrictMap := e.isHomeomorph.isStrictMap isClosed_range := by simp - finite_ker := by --show FiniteDimensional 𝕜 e.toLinearEquiv.toLinearMap.ker by - rw [LinearMap.ker_eq_bot.2 (by exact EquivLike.injective e)] + finite_ker := by + rw [LinearMap.ker_eq_bot.2 (by exact e.injective)] infer_instance finite_coker := by simp closedComplemented_ker := by simp From e8459ee0e879f1b23a434eaecde96deb9c9f98cf Mon Sep 17 00:00:00 2001 From: ADedecker Date: Fri, 10 Jul 2026 21:55:12 +0200 Subject: [PATCH 210/210] Better --- Mathlib/Analysis/FredholmOperator.lean | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Mathlib/Analysis/FredholmOperator.lean b/Mathlib/Analysis/FredholmOperator.lean index e795472591e3ef..75c7544b8dae72 100644 --- a/Mathlib/Analysis/FredholmOperator.lean +++ b/Mathlib/Analysis/FredholmOperator.lean @@ -383,6 +383,19 @@ end DefTFAE section Constructions +theorem _root_.ContinuousLinearEquiv.isFredholm (e : E ≃L[𝕜] F) : + IsFredholm (e : E →L[𝕜] F) where + isStrictMap := e.isHomeomorph.isStrictMap + isClosed_range := by simp + finite_ker := by + rw [LinearMap.ker_eq_bot.2 (by exact e.injective)] + infer_instance + finite_coker := by simp + closedComplemented_ker := by simp + +theorem IsFredholm.id : IsFredholm (.id 𝕜 E) := + ContinuousLinearEquiv.refl 𝕜 E |>.isFredholm + variable [CompleteSpace 𝕜] [IsTopologicalAddGroup E] [IsTopologicalAddGroup F] [IsTopologicalAddGroup G] [ContinuousSMul 𝕜 E] [ContinuousSMul 𝕜 F] [ContinuousSMul 𝕜 G] [T2Space E] [T2Space F] [T2Space G] @@ -420,14 +433,6 @@ theorem IsFredholm.comp_iff_right {f : E →L[𝕜] F} {f' : F →L[𝕜] G} (hf rcases hcomp with ⟨w, hw⟩ exact ⟨w ∘L f', .symm <| hg'.symm.of_comp_right hw.symm⟩ -theorem _root_.ContinuousLinearEquiv.isFredholm (e : E ≃L[𝕜] F) : - IsFredholm (e : E →L[𝕜] F) := - isFredholm_iff_exists_isQuasiInverse.mpr - ⟨e.symm, by simp [IsQuasiInverse, IsLeftQuasiInverse, IsRightQuasiInverse]⟩ - -theorem IsFredholm.id : IsFredholm (.id 𝕜 E) := - ContinuousLinearEquiv.refl 𝕜 E |>.isFredholm - end Constructions end ContinuousLinearMap