Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit 3bf7241

Browse files
committed
feat(algebra/algebra,linear_algebra): add *_equiv.of_left_inverse (#6167)
The main purpose of this change is to add equivalences onto the range of a function with a left-inverse: * `algebra_equiv.of_left_inverse` * `linear_equiv.of_left_inverse` * `ring_equiv.of_left_inverse` * `ring_equiv.sof_left_inverse` (the sub***S***emiring version) This also: * Renames `alg_hom.alg_equiv.of_injective` to `alg_equiv.of_injective` * Adds `subalgebra.mem_range_self` and `subsemiring.mem_srange_self` for consistency with `subring.mem_range_self` * Replaces `subring.surjective_onto_range` with `subring.range_restrict_surjective`, which have defeq statements These are computable versions of `*_equiv.of_injective`, with the benefit of having a known inverse, and in the case of `linear_equiv` working for `semiring` and not just `ring`.
1 parent 2289b18 commit 3bf7241

File tree

9 files changed

+148
-31
lines changed

9 files changed

+148
-31
lines changed

src/algebra/algebra/subalgebra.lean

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,8 @@ protected def range (φ : A →ₐ[R] B) : subalgebra R B :=
290290
@[simp] lemma mem_range (φ : A →ₐ[R] B) {y : B} :
291291
y ∈ φ.range ↔ ∃ x, φ x = y := ring_hom.mem_srange
292292

293+
theorem mem_range_self (φ : A →ₐ[R] B) (x : A) : φ x ∈ φ.range := φ.mem_range.2 ⟨x, rfl⟩
294+
293295
@[simp] lemma coe_range (φ : A →ₐ[R] B) : (φ.range : set B) = set.range φ :=
294296
by { ext, rw [subalgebra.mem_coe, mem_range], refl }
295297

@@ -298,24 +300,22 @@ def cod_restrict (f : A →ₐ[R] B) (S : subalgebra R B) (hf : ∀ x, f x ∈ S
298300
{ commutes' := λ r, subtype.eq $ f.commutes r,
299301
.. ring_hom.cod_srestrict (f : A →+* B) S hf }
300302

303+
@[simp] lemma val_comp_cod_restrict (f : A →ₐ[R] B) (S : subalgebra R B) (hf : ∀ x, f x ∈ S) :
304+
S.val.comp (f.cod_restrict S hf) = f :=
305+
alg_hom.ext $ λ _, rfl
306+
307+
@[simp] lemma coe_cod_restrict (f : A →ₐ[R] B) (S : subalgebra R B) (hf : ∀ x, f x ∈ S) (x : A) :
308+
↑(f.cod_restrict S hf x) = f x := rfl
309+
301310
theorem injective_cod_restrict (f : A →ₐ[R] B) (S : subalgebra R B) (hf : ∀ x, f x ∈ S) :
302311
function.injective (f.cod_restrict S hf) ↔ function.injective f :=
303312
⟨λ H x y hxy, H $ subtype.eq hxy, λ H x y hxy, H (congr_arg subtype.val hxy : _)⟩
304313

305-
/-- Restrict an injective algebra homomorphism to an algebra isomorphism -/
306-
noncomputable def alg_equiv.of_injective (f : A →ₐ[R] B) (hf : function.injective f) :
307-
A ≃ₐ[R] f.range :=
308-
alg_equiv.of_bijective (f.cod_restrict f.range (λ x, f.mem_range.mpr ⟨x, rfl⟩))
309-
⟨(f.injective_cod_restrict f.range (λ x, f.mem_range.mpr ⟨x, rfl⟩)).mpr hf,
310-
λ x, Exists.cases_on (f.mem_range.mp (subtype.mem x)) (λ y hy, ⟨y, subtype.ext hy⟩)⟩
311-
312-
@[simp] lemma alg_equiv.of_injective_apply (f : A →ₐ[R] B) (hf : function.injective f) (x : A) :
313-
↑(alg_equiv.of_injective f hf x) = f x := rfl
314+
/-- Restrict the codomain of a alg_hom `f` to `f.range`.
314315
315-
/-- Restrict an algebra homomorphism between fields to an algebra isomorphism -/
316-
noncomputable def alg_equiv.of_injective_field {E F : Type*} [division_ring E] [semiring F]
317-
[nontrivial F] [algebra R E] [algebra R F] (f : E →ₐ[R] F) : E ≃ₐ[R] f.range :=
318-
alg_equiv.of_injective f f.to_ring_hom.injective
316+
This is the bundled version of `set.range_factorization`. -/
317+
@[reducible] def range_restrict (f : A →ₐ[R] B) : A →ₐ[R] f.range :=
318+
f.cod_restrict f.range f.mem_range_self
319319

320320
/-- The equalizer of two R-algebra homomorphisms -/
321321
def equalizer (ϕ ψ : A →ₐ[R] B) : subalgebra R A :=
@@ -341,6 +341,48 @@ def equalizer (ϕ ψ : A →ₐ[R] B) : subalgebra R A :=
341341

342342
end alg_hom
343343

344+
namespace alg_equiv
345+
346+
variables {R : Type u} {A : Type v} {B : Type w}
347+
variables [comm_semiring R] [semiring A] [semiring B] [algebra R A] [algebra R B]
348+
349+
/-- Restrict an algebra homomorphism with a left inverse to an algebra isomorphism to its range.
350+
351+
This is a computable alternative to `alg_equiv.of_injective`. -/
352+
def of_left_inverse
353+
{g : B → A} {f : A →ₐ[R] B} (h : function.left_inverse g f) :
354+
A ≃ₐ[R] f.range :=
355+
{ to_fun := f.range_restrict,
356+
inv_fun := g ∘ f.range.val,
357+
left_inv := h,
358+
right_inv := λ x, subtype.ext $
359+
let ⟨x', hx'⟩ := f.mem_range.mp x.prop in
360+
show f (g x) = x, by rw [←hx', h x'],
361+
..f.range_restrict }
362+
363+
@[simp] lemma of_left_inverse_apply
364+
{g : B → A} {f : A →ₐ[R] B} (h : function.left_inverse g f) (x : A) :
365+
↑(of_left_inverse h x) = f x := rfl
366+
367+
@[simp] lemma of_left_inverse_symm_apply
368+
{g : B → A} {f : A →ₐ[R] B} (h : function.left_inverse g f) (x : f.range) :
369+
(of_left_inverse h).symm x = g x := rfl
370+
371+
/-- Restrict an injective algebra homomorphism to an algebra isomorphism -/
372+
noncomputable def of_injective (f : A →ₐ[R] B) (hf : function.injective f) :
373+
A ≃ₐ[R] f.range :=
374+
of_left_inverse (classical.some_spec hf.has_left_inverse)
375+
376+
@[simp] lemma of_injective_apply (f : A →ₐ[R] B) (hf : function.injective f) (x : A) :
377+
↑(of_injective f hf x) = f x := rfl
378+
379+
/-- Restrict an algebra homomorphism between fields to an algebra isomorphism -/
380+
noncomputable def of_injective_field {E F : Type*} [division_ring E] [semiring F]
381+
[nontrivial F] [algebra R E] [algebra R F] (f : E →ₐ[R] F) : E ≃ₐ[R] f.range :=
382+
of_injective f f.to_ring_hom.injective
383+
384+
end alg_equiv
385+
344386
namespace algebra
345387

346388
variables (R : Type u) {A : Type v} {B : Type w}

src/field_theory/normal.lean

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,13 +216,13 @@ def alg_hom.restrict_normal_aux [h : normal F E] :
216216

217217
/-- Restrict algebra homomorphism to normal subfield -/
218218
def alg_hom.restrict_normal [normal F E] : E →ₐ[F] E :=
219-
((alg_hom.alg_equiv.of_injective_field (is_scalar_tower.to_alg_hom F E K)).symm.to_alg_hom.comp
219+
((alg_equiv.of_injective_field (is_scalar_tower.to_alg_hom F E K)).symm.to_alg_hom.comp
220220
(ϕ.restrict_normal_aux E)).comp
221-
(alg_hom.alg_equiv.of_injective_field (is_scalar_tower.to_alg_hom F E K)).to_alg_hom
221+
(alg_equiv.of_injective_field (is_scalar_tower.to_alg_hom F E K)).to_alg_hom
222222

223223
@[simp] lemma alg_hom.restrict_normal_commutes [normal F E] (x : E) :
224224
algebra_map E K (ϕ.restrict_normal E x) = ϕ (algebra_map E K x) :=
225-
subtype.ext_iff.mp (alg_equiv.apply_symm_apply (alg_hom.alg_equiv.of_injective_field
225+
subtype.ext_iff.mp (alg_equiv.apply_symm_apply (alg_equiv.of_injective_field
226226
(is_scalar_tower.to_alg_hom F E K)) (ϕ.restrict_normal_aux E
227227
⟨is_scalar_tower.to_alg_hom F E K x, ⟨x, ⟨subsemiring.mem_top x, rfl⟩⟩⟩))
228228

src/field_theory/polynomial_galois_group.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ variables {p E}
123123
@[simp] lemma restrict_smul [h : fact (p.splits (algebra_map F E))]
124124
(ϕ : E ≃ₐ[F] E) (x : root_set p E) : ↑((restrict p E ϕ) • x) = ϕ x :=
125125
begin
126-
let ψ := alg_hom.alg_equiv.of_injective_field (is_scalar_tower.to_alg_hom F p.splitting_field E),
126+
let ψ := alg_equiv.of_injective_field (is_scalar_tower.to_alg_hom F p.splitting_field E),
127127
change ↑(ψ (ψ.symm _)) = ϕ x,
128128
rw alg_equiv.apply_symm_apply ψ,
129129
change ϕ (roots_equiv_roots p E ((roots_equiv_roots p E).symm x)) = ϕ x,

src/linear_algebra/basic.lean

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,7 +1286,9 @@ by rw [range, map_le_iff_le_comap, eq_top_iff]
12861286
lemma map_le_range {f : M →ₗ[R] M₂} {p : submodule R M} : map f p ≤ range f :=
12871287
map_mono le_top
12881288

1289-
/-- Restrict the codomain of a linear map `f` to `f.range`. -/
1289+
/-- Restrict the codomain of a linear map `f` to `f.range`.
1290+
1291+
This is the bundled version of `set.range_factorization`. -/
12901292
@[reducible] def range_restrict (f : M →ₗ[R] M₂) : M →ₗ[R] f.range :=
12911293
f.cod_restrict f.range f.mem_range_self
12921294

@@ -1848,6 +1850,30 @@ end
18481850
@[simp] protected theorem ker : (e : M →ₗ[R] M₂).ker = ⊥ :=
18491851
linear_map.ker_eq_bot_of_injective e.to_equiv.injective
18501852

1853+
variables {f g}
1854+
1855+
/-- An linear map `f : M →ₗ[R] M₂` with a left-inverse `g : M₂ →ₗ[R] M` defines a linear equivalence
1856+
between `M` and `f.range`.
1857+
1858+
This is a computable alternative to `linear_equiv.of_injective`, and a bidirectional version of
1859+
`linear_map.range_restrict`. -/
1860+
def of_left_inverse {g : M₂ → M} (h : function.left_inverse g f) : M ≃ₗ[R] f.range :=
1861+
{ to_fun := f.range_restrict,
1862+
inv_fun := g ∘ f.range.subtype,
1863+
left_inv := h,
1864+
right_inv := λ x, subtype.ext $
1865+
let ⟨x', hx'⟩ := linear_map.mem_range.mp x.prop in
1866+
show f (g x) = x, by rw [←hx', h x'],
1867+
.. f.range_restrict }
1868+
1869+
@[simp] lemma of_left_inverse_apply
1870+
(h : function.left_inverse g f) (x : M) :
1871+
↑(of_left_inverse h x) = f x := rfl
1872+
1873+
@[simp] lemma of_left_inverse_symm_apply
1874+
(h : function.left_inverse g f) (x : f.range) :
1875+
(of_left_inverse h).symm x = g x := rfl
1876+
18511877
end
18521878

18531879
end add_comm_monoid
@@ -1890,10 +1916,9 @@ variables {semimodule_M : semimodule R M} {semimodule_M₂ : semimodule R M₂}
18901916
variables (f : M →ₗ[R] M₂) (e : M ≃ₗ[R] M₂)
18911917

18921918
/-- An `injective` linear map `f : M →ₗ[R] M₂` defines a linear equivalence
1893-
between `M` and `f.range`. -/
1919+
between `M` and `f.range`. See also `linear_map.of_left_inverse`. -/
18941920
noncomputable def of_injective (h : f.ker = ⊥) : M ≃ₗ[R] f.range :=
1895-
{ .. (equiv.set.range f $ linear_map.ker_eq_bot.1 h).trans (equiv.set.of_eq f.range_coe.symm),
1896-
.. f.cod_restrict f.range (λ x, f.mem_range_self x) }
1921+
of_left_inverse $ classical.some_spec (linear_map.ker_eq_bot.1 h).has_left_inverse
18971922

18981923
@[simp] theorem of_injective_apply {h : f.ker = ⊥} (x : M) :
18991924
↑(of_injective f h x) = f x := rfl

src/ring_theory/jacobson.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ begin
372372
introI hI,
373373
let R' : subring I.quotient := ((quotient.mk I).comp C).range,
374374
let i : R →+* R' := ((quotient.mk I).comp C).range_restrict,
375-
have hi : function.surjective (i : R → R') := ((quotient.mk I).comp C).surjective_onto_range,
375+
have hi : function.surjective (i : R → R') := ((quotient.mk I).comp C).range_restrict_surjective,
376376
have hi' : (polynomial.map_ring_hom i : polynomial R →+* polynomial R').ker ≤ I,
377377
{ refine λ f hf, polynomial_mem_ideal_of_coeff_mem_ideal I f (λ n, _),
378378
replace hf := congr_arg (λ (g : polynomial (((quotient.mk I).comp C).range)), g.coeff n) hf,

src/ring_theory/noetherian.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -516,8 +516,8 @@ end
516516

517517
instance is_noetherian_ring_range {R} [comm_ring R] {S} [comm_ring S] (f : R →+* S)
518518
[is_noetherian_ring R] : is_noetherian_ring f.range :=
519-
is_noetherian_ring_of_surjective R f.range (f.cod_restrict' f.range f.mem_range_self)
520-
f.surjective_onto_range
519+
is_noetherian_ring_of_surjective R f.range f.range_restrict
520+
f.range_restrict_surjective
521521

522522
theorem is_noetherian_ring_of_ring_equiv (R) [comm_ring R] {S} [comm_ring S]
523523
(f : R ≃+* S) [is_noetherian_ring R] : is_noetherian_ring S :=

src/ring_theory/polynomial/basic.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ begin
347347
simp only [ring_hom.comp_apply, quotient.eq_zero_iff_mem, subring.coe_zero, subtype.val_eq_coe],
348348
suffices : C (i y) ∈ (I.map (polynomial.map_ring_hom i)),
349349
{ obtain ⟨f, hf⟩ := mem_image_of_mem_map_of_surjective (polynomial.map_ring_hom i)
350-
(polynomial.map_surjective _ (((quotient.mk I).comp C).surjective_onto_range)) this,
350+
(polynomial.map_surjective _ (((quotient.mk I).comp C).range_restrict_surjective)) this,
351351
refine sub_add_cancel (C y) f ▸ I.add_mem (hi' _ : (C y - f) ∈ I) hf.1,
352352
rw [ring_hom.mem_ker, ring_hom.map_sub, hf.2, sub_eq_zero_iff_eq, coe_map_ring_hom, map_C] },
353353
exact hx,

src/ring_theory/subring.lean

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -359,9 +359,6 @@ def cod_restrict' {R : Type u} {S : Type v} [ring R] [ring S] (f : R →+* S)
359359
map_mul' := λ x y, subtype.eq $ f.map_mul x y,
360360
map_one' := subtype.eq f.map_one }
361361

362-
lemma surjective_onto_range : function.surjective (f.cod_restrict' f.range f.mem_range_self) :=
363-
λ ⟨y, hy⟩, let ⟨x, hx⟩ := mem_range.mp hy in ⟨x, subtype.ext hx⟩
364-
365362
end ring_hom
366363

367364
namespace subring
@@ -639,12 +636,17 @@ def restrict (f : R →+* S) (s : subring R) : s →+* S := f.comp s.subtype
639636

640637
@[simp] lemma restrict_apply (f : R →+* S) (x : s) : f.restrict s x = f x := rfl
641638

642-
/-- Restriction of a ring homomorphism to its range interpreted as a subsemiring. -/
639+
/-- Restriction of a ring homomorphism to its range interpreted as a subsemiring.
640+
641+
This is the bundled version of `set.range_factorization`. -/
643642
def range_restrict (f : R →+* S) : R →+* f.range :=
644643
f.cod_restrict' f.range $ λ x, ⟨x, subring.mem_top x, rfl⟩
645644

646645
@[simp] lemma coe_range_restrict (f : R →+* S) (x : R) : (f.range_restrict x : S) = f x := rfl
647646

647+
lemma range_restrict_surjective (f : R →+* S) : function.surjective f.range_restrict :=
648+
λ ⟨y, hy⟩, let ⟨x, hx⟩ := mem_range.mp hy in ⟨x, subtype.ext hx⟩
649+
648650
lemma range_top_iff_surjective {f : R →+* S} :
649651
f.range = (⊤ : subring S) ↔ function.surjective f :=
650652
subring.ext'_iff.trans $ iff.trans (by rw [coe_range, coe_top]) set.range_iff_surjective
@@ -725,6 +727,26 @@ variables {s t : subring R}
725727
def subring_congr (h : s = t) : s ≃+* t :=
726728
{ map_mul' := λ _ _, rfl, map_add' := λ _ _, rfl, ..equiv.set_congr $ subring.ext'_iff.1 h }
727729

730+
/-- Restrict a ring homomorphism with a left inverse to a ring isomorphism to its
731+
`ring_hom.range`. -/
732+
def of_left_inverse {g : S → R} {f : R →+* S} (h : function.left_inverse g f) :
733+
R ≃+* f.range :=
734+
{ to_fun := λ x, f.range_restrict x,
735+
inv_fun := λ x, (g ∘ f.range.subtype) x,
736+
left_inv := h,
737+
right_inv := λ x, subtype.ext $
738+
let ⟨x', hx'⟩ := ring_hom.mem_range.mp x.prop in
739+
show f (g x) = x, by rw [←hx', h x'],
740+
..f.range_restrict }
741+
742+
@[simp] lemma of_left_inverse_apply
743+
{g : S → R} {f : R →+* S} (h : function.left_inverse g f) (x : R) :
744+
↑(of_left_inverse h x) = f x := rfl
745+
746+
@[simp] lemma of_left_inverse_symm_apply
747+
{g : S → R} {f : R →+* S} (h : function.left_inverse g f) (x : f.range) :
748+
(of_left_inverse h).symm x = g x := rfl
749+
728750
end ring_equiv
729751

730752
namespace subring

src/ring_theory/subsemiring.lean

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,9 @@ def srange : subsemiring S := (⊤ : subsemiring R).map f
259259
@[simp] lemma mem_srange {f : R →+* S} {y : S} : y ∈ f.srange ↔ ∃ x, f x = y :=
260260
by simp [srange]
261261

262+
lemma mem_srange_self (f : R →+* S) (x : R) : f x ∈ f.srange :=
263+
mem_srange.mpr ⟨x, rfl⟩
264+
262265
lemma map_srange : f.srange.map g = (g.comp f).srange :=
263266
(⊤ : subsemiring R).map_map g f
264267

@@ -517,14 +520,19 @@ def cod_srestrict (f : R →+* S) (s : subsemiring S) (h : ∀ x, f x ∈ s) : R
517520
.. (f : R →* S).cod_mrestrict s.to_submonoid h,
518521
.. (f : R →+ S).cod_mrestrict s.to_add_submonoid h }
519522

520-
/-- Restriction of a ring homomorphism to its range iterpreted as a subsemiring. -/
523+
/-- Restriction of a ring homomorphism to its range interpreted as a subsemiring.
524+
525+
This is the bundled version of `set.range_factorization`. -/
521526
def srange_restrict (f : R →+* S) : R →+* f.srange :=
522-
f.cod_srestrict f.srange $ λ x, ⟨x, subsemiring.mem_top x, rfl⟩
527+
f.cod_srestrict f.srange f.mem_srange_self
523528

524529
@[simp] lemma coe_srange_restrict (f : R →+* S) (x : R) :
525530
(f.srange_restrict x : S) = f x :=
526531
rfl
527532

533+
lemma srange_restrict_surjective (f : R →+* S) : function.surjective f.srange_restrict :=
534+
λ ⟨y, hy⟩, let ⟨x, hx⟩ := mem_srange.mp hy in ⟨x, subtype.ext hx⟩
535+
528536
lemma srange_top_iff_surjective {f : R →+* S} :
529537
f.srange = (⊤ : subsemiring S) ↔ function.surjective f :=
530538
subsemiring.ext'_iff.trans $ iff.trans (by rw [coe_srange, coe_top]) set.range_iff_surjective
@@ -604,4 +612,24 @@ variables {s t : subsemiring R}
604612
def subsemiring_congr (h : s = t) : s ≃+* t :=
605613
{ map_mul' := λ _ _, rfl, map_add' := λ _ _, rfl, ..equiv.set_congr $ subsemiring.ext'_iff.1 h }
606614

615+
/-- Restrict a ring homomorphism with a left inverse to a ring isomorphism to its
616+
`ring_hom.srange`. -/
617+
def sof_left_inverse {g : S → R} {f : R →+* S} (h : function.left_inverse g f) :
618+
R ≃+* f.srange :=
619+
{ to_fun := λ x, f.srange_restrict x,
620+
inv_fun := λ x, (g ∘ f.srange.subtype) x,
621+
left_inv := h,
622+
right_inv := λ x, subtype.ext $
623+
let ⟨x', hx'⟩ := ring_hom.mem_srange.mp x.prop in
624+
show f (g x) = x, by rw [←hx', h x'],
625+
..f.srange_restrict }
626+
627+
@[simp] lemma sof_left_inverse_apply
628+
{g : S → R} {f : R →+* S} (h : function.left_inverse g f) (x : R) :
629+
↑(sof_left_inverse h x) = f x := rfl
630+
631+
@[simp] lemma sof_left_inverse_symm_apply
632+
{g : S → R} {f : R →+* S} (h : function.left_inverse g f) (x : f.srange) :
633+
(sof_left_inverse h).symm x = g x := rfl
634+
607635
end ring_equiv

0 commit comments

Comments
 (0)