Skip to content

Commit

Permalink
refactor(Data/FunLike): use unbundled inheritance from FunLike (#8386)
Browse files Browse the repository at this point in the history
The FunLike hierarchy is very big and gets scanned through each time we need a coercion (via the `CoeFun` instance). It looks like unbundled inheritance suits Lean 4 better here. The only class that still extends `FunLike` is `EquivLike`, since that has a custom `coe_injective'` field that is easier to implement. All other classes should take `FunLike` or `EquivLike` as a parameter.

[Zulip thread](https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/.60example.20.28p.20.3A.20P.29.20.3A.20Q.20.3A.3D.20p.60.20takes.200.2E25s.20to.20fail!)

## Important changes

Previously, morphism classes would be `Type`-valued and extend `FunLike`:
```lean
/-- `MyHomClass F A B` states that `F` is a type of `MyClass.op`-preserving morphisms.
You should extend this class when you extend `MyHom`. -/
class MyHomClass (F : Type*) (A B : outParam <| Type*) [MyClass A] [MyClass B]
  extends FunLike F A B :=
(map_op : ∀ (f : F) (x y : A), f (MyClass.op x y) = MyClass.op (f x) (f y))
```
After this PR, they should be `Prop`-valued and take `FunLike` as a parameter:
```lean
/-- `MyHomClass F A B` states that `F` is a type of `MyClass.op`-preserving morphisms.
You should extend this class when you extend `MyHom`. -/
class MyHomClass (F : Type*) (A B : outParam <| Type*) [MyClass A] [MyClass B]
  [FunLike F A B] : Prop :=
(map_op : ∀ (f : F) (x y : A), f (MyClass.op x y) = MyClass.op (f x) (f y))
```
(Note that `A B` stay marked as `outParam` even though they are not purely required to be so due to the `FunLike` parameter already filling them in. This is required to see through type synonyms, which is important in the category theory library. Also, I think keeping them as `outParam` is slightly faster.)

Similarly, `MyEquivClass` should take `EquivLike` as a parameter.

As a result, every mention of `[MyHomClass F A B]` should become `[FunLike F A B] [MyHomClass F A B]`.

## Remaining issues

### Slower (failing) search

While overall this gives some great speedups, there are some cases that are noticeably slower. In particular, a *failing* application of a lemma such as `map_mul` is more expensive. This is due to suboptimal processing of arguments. For example:
```lean
variable [FunLike F M N] [Mul M] [Mul N] (f : F) (x : M) (y : M)

theorem map_mul [MulHomClass F M N] : f (x * y) = f x * f y

example [AddHomClass F A B] : f (x * y) = f x * f y := map_mul f _ _
```
Before this PR, applying `map_mul f` gives the goals `[Mul ?M] [Mul ?N] [MulHomClass F ?M ?N]`. Since `M` and `N` are `out_param`s, `[MulHomClass F ?M ?N]` is synthesized first, supplies values for `?M` and `?N` and then the `Mul M` and `Mul N` instances can be found.

After this PR, the goals become `[FunLike F ?M ?N] [Mul ?M] [Mul ?N] [MulHomClass F ?M ?N]`. Now `[FunLike F ?M ?N]` is synthesized first, supplies values for `?M` and `?N` and then the `Mul M` and `Mul N` instances can be found, before trying `MulHomClass F M N` which *fails*. Since the `Mul` hierarchy is very big, this can be slow to fail, especially when there is no such `Mul` instance.

A long-term but harder to achieve solution would be to specify the order in which instance goals get solved. For example, we'd like to change the arguments to `map_mul` to look like `[FunLike F M N] [Mul M] [Mul N] [highPriority <| MulHomClass F M N]` because `MulHomClass` fails or succeeds much faster than the others.

As a consequence, the `simpNF` linter is much slower since by design it tries and fails to apply many `map_` lemmas. The same issue occurs a few times in existing calls to `simp [map_mul]`, where `map_mul` is tried "too soon" and fails. Thanks to the speedup of leanprover/lean4#2478 the impact is very limited, only in files that already were close to the timeout.

### `simp` not firing sometimes

This affects `map_smulₛₗ` and related definitions. For `simp` lemmas Lean apparently uses a slightly different mechanism to find instances, so that `rw` can find every argument to `map_smulₛₗ` successfully but `simp` can't: leanprover/lean4#3701.

### Missing instances due to unification failing

Especially in the category theory library, we might sometimes have a type `A` which is also accessible as a synonym `(Bundled A hA).1`. Instance synthesis doesn't always work if we have `f : A →* B` but `x * y : (Bundled A hA).1` or vice versa. This seems to be mostly fixed by keeping `A B` as `outParam`s in `MulHomClass F A B`. (Presumably because Lean will do a definitional check `A =?= (Bundled A hA).1` instead of using the syntax in the discrimination tree.)

## Workaround for issues

The timeouts can be worked around for now by specifying which `map_mul` we mean, either as `map_mul f` for some explicit `f`, or as e.g. `MonoidHomClass.map_mul`.

`map_smulₛₗ` not firing as `simp` lemma can be worked around by going back to the pre-FunLike situation and making `LinearMap.map_smulₛₗ` a `simp` lemma instead of the generic `map_smulₛₗ`. Writing `simp [map_smulₛₗ _]` also works.



Co-authored-by: Matthew Ballard <[email protected]>
Co-authored-by: Scott Morrison <[email protected]>
Co-authored-by: Scott Morrison <[email protected]>
Co-authored-by: Anne Baanen <[email protected]>
  • Loading branch information
5 people committed Feb 5, 2024
1 parent 55f0d23 commit c6a73d4
Show file tree
Hide file tree
Showing 248 changed files with 1,847 additions and 1,376 deletions.
56 changes: 23 additions & 33 deletions Mathlib/Algebra/Algebra/Equiv.lean
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ notation:50 A " ≃ₐ[" R "] " A' => AlgEquiv R A A'
/-- `AlgEquivClass F R A B` states that `F` is a type of algebra structure preserving
equivalences. You should extend this class when you extend `AlgEquiv`. -/
class AlgEquivClass (F : Type*) (R A B : outParam (Type*)) [CommSemiring R] [Semiring A]
[Semiring B] [Algebra R A] [Algebra R B] extends RingEquivClass F A B where
[Semiring B] [Algebra R A] [Algebra R B] [EquivLike F A B]
extends RingEquivClass F A B : Prop where
/-- An equivalence of algebras commutes with the action of scalars. -/
commutes : ∀ (f : F) (r : R), f (algebraMap R A r) = algebraMap R B r
#align alg_equiv_class AlgEquivClass
Expand All @@ -57,30 +58,26 @@ namespace AlgEquivClass

-- See note [lower instance priority]
instance (priority := 100) toAlgHomClass (F R A B : Type*) [CommSemiring R] [Semiring A]
[Semiring B] [Algebra R A] [Algebra R B] [h : AlgEquivClass F R A B] :
[Semiring B] [Algebra R A] [Algebra R B] [EquivLike F A B] [h : AlgEquivClass F R A B] :
AlgHomClass F R A B :=
{ h with
coe := (⇑)
coe_injective' := DFunLike.coe_injective
map_zero := map_zero
map_one := map_one }
{ h with }
#align alg_equiv_class.to_alg_hom_class AlgEquivClass.toAlgHomClass

instance (priority := 100) toLinearEquivClass (F R A B : Type*) [CommSemiring R]
[Semiring A] [Semiring B] [Algebra R A] [Algebra R B]
[h : AlgEquivClass F R A B] : LinearEquivClass F R A B :=
[EquivLike F A B] [h : AlgEquivClass F R A B] : LinearEquivClass F R A B :=
{ h with map_smulₛₗ := fun f => map_smulₛₗ f }
#align alg_equiv_class.to_linear_equiv_class AlgEquivClass.toLinearEquivClass

/-- Turn an element of a type `F` satisfying `AlgEquivClass F R A B` into an actual `AlgEquiv`.
This is declared as the default coercion from `F` to `A ≃ₐ[R] B`. -/
@[coe]
def toAlgEquiv {F R A B : Type*} [CommSemiring R] [Semiring A] [Semiring B] [Algebra R A]
[Algebra R B] [AlgEquivClass F R A B] (f : F) : A ≃ₐ[R] B :=
[Algebra R B] [EquivLike F A B] [AlgEquivClass F R A B] (f : F) : A ≃ₐ[R] B :=
{ (f : A ≃ B), (f : A ≃+* B) with commutes' := commutes f }

instance (F R A B : Type*) [CommSemiring R] [Semiring A] [Semiring B] [Algebra R A] [Algebra R B]
[AlgEquivClass F R A B] : CoeTC F (A ≃ₐ[R] B) :=
[EquivLike F A B] [AlgEquivClass F R A B] : CoeTC F (A ≃ₐ[R] B) :=
⟨toAlgEquiv⟩
end AlgEquivClass

Expand All @@ -101,25 +98,6 @@ variable [Algebra R A₁'] [Algebra R A₂'] [Algebra R A₃']

variable (e : A₁ ≃ₐ[R] A₂)

instance : AlgEquivClass (A₁ ≃ₐ[R] A₂) R A₁ A₂ where
coe f := f.toFun
inv f := f.invFun
coe_injective' f g h₁ h₂ := by
obtain ⟨⟨f,_⟩,_⟩ := f
obtain ⟨⟨g,_⟩,_⟩ := g
congr
map_add f := f.map_add'
map_mul f := f.map_mul'
commutes f := f.commutes'
left_inv f := f.left_inv
right_inv f := f.right_inv

-- Porting note: replaced with EquivLike instance
-- /-- Helper instance for when there's too many metavariables to apply
-- `fun_like.has_coe_to_fun` directly. -/
-- instance : CoeFun (A₁ ≃ₐ[R] A₂) fun _ => A₁ → A₂ :=
-- ⟨AlgEquiv.toFun⟩

instance : EquivLike (A₁ ≃ₐ[R] A₂) A₁ A₂ where
coe f := f.toFun
inv f := f.invFun
Expand All @@ -130,7 +108,17 @@ instance : EquivLike (A₁ ≃ₐ[R] A₂) A₁ A₂ where
obtain ⟨⟨g,_⟩,_⟩ := g
congr

-- Porting note: the default simps projection was `e.toEquiv.toFun`, it should be `DFunLike.coe`
/-- Helper instance since the coercion is not always found. -/
instance : FunLike (A₁ ≃ₐ[R] A₂) A₁ A₂ where
coe := DFunLike.coe
coe_injective' := DFunLike.coe_injective'

instance : AlgEquivClass (A₁ ≃ₐ[R] A₂) R A₁ A₂ where
map_add f := f.map_add'
map_mul f := f.map_mul'
commutes f := f.commutes'

-- Porting note: the default simps projection was `e.toEquiv.toFun`, it should be `FunLike.coe`
/-- See Note [custom simps projection] -/
def Simps.apply (e : A₁ ≃ₐ[R] A₂) : A₁ → A₂ :=
e
Expand All @@ -142,7 +130,7 @@ def Simps.toEquiv (e : A₁ ≃ₐ[R] A₂) : A₁ ≃ A₂ :=

-- Porting note: `protected` used to be an attribute below
@[simp]
protected theorem coe_coe {F : Type*} [AlgEquivClass F R A₁ A₂] (f : F) :
protected theorem coe_coe {F : Type*} [EquivLike F A₁ A₂] [AlgEquivClass F R A₁ A₂] (f : F) :
⇑(f : A₁ ≃ₐ[R] A₂) = f :=
rfl
#align alg_equiv.coe_coe AlgEquiv.coe_coe
Expand Down Expand Up @@ -341,13 +329,15 @@ def Simps.symm_apply (e : A₁ ≃ₐ[R] A₂) : A₂ → A₁ :=
initialize_simps_projections AlgEquiv (toFun → apply, invFun → symm_apply)

--@[simp] -- Porting note: simp can prove this once symm_mk is introduced
theorem coe_apply_coe_coe_symm_apply {F : Type*} [AlgEquivClass F R A₁ A₂] (f : F) (x : A₂) :
theorem coe_apply_coe_coe_symm_apply {F : Type*} [EquivLike F A₁ A₂] [AlgEquivClass F R A₁ A₂]
(f : F) (x : A₂) :
f ((f : A₁ ≃ₐ[R] A₂).symm x) = x :=
EquivLike.right_inv f x
#align alg_equiv.coe_apply_coe_coe_symm_apply AlgEquiv.coe_apply_coe_coe_symm_apply

--@[simp] -- Porting note: simp can prove this once symm_mk is introduced
theorem coe_coe_symm_apply_coe_apply {F : Type*} [AlgEquivClass F R A₁ A₂] (f : F) (x : A₁) :
theorem coe_coe_symm_apply_coe_apply {F : Type*} [EquivLike F A₁ A₂] [AlgEquivClass F R A₁ A₂]
(f : F) (x : A₁) :
(f : A₁ ≃ₐ[R] A₂).symm (f x) = x :=
EquivLike.left_inv f x
#align alg_equiv.coe_coe_symm_apply_coe_apply AlgEquiv.coe_coe_symm_apply_coe_apply
Expand Down
21 changes: 12 additions & 9 deletions Mathlib/Algebra/Algebra/Hom.lean
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ notation:25 A " →ₐ[" R "] " B => AlgHom R A B

/-- `AlgHomClass F R A B` asserts `F` is a type of bundled algebra homomorphisms
from `A` to `B`. -/
class AlgHomClass (F : Type*) (R : outParam (Type*)) (A : outParam (Type*))
(B : outParam (Type*)) [CommSemiring R] [Semiring A] [Semiring B] [Algebra R A]
[Algebra R B] extends RingHomClass F A B where
class AlgHomClass (F : Type*) (R A B : outParam Type*)
[CommSemiring R] [Semiring A] [Semiring B] [Algebra R A] [Algebra R B]
[FunLike F A B] extends RingHomClass F A B : Prop where
commutes : ∀ (f : F) (r : R), f (algebraMap R A r) = algebraMap R B r
#align alg_hom_class AlgHomClass

Expand All @@ -63,7 +63,7 @@ class AlgHomClass (F : Type*) (R : outParam (Type*)) (A : outParam (Type*))
namespace AlgHomClass

variable {R : Type*} {A : Type*} {B : Type*} [CommSemiring R] [Semiring A] [Semiring B]
[Algebra R A] [Algebra R B]
[Algebra R A] [Algebra R B] [FunLike F A B]

-- see Note [lower instance priority]
instance (priority := 100) linearMapClass [AlgHomClass F R A B] : LinearMapClass F R A B :=
Expand All @@ -76,12 +76,12 @@ instance (priority := 100) linearMapClass [AlgHomClass F R A B] : LinearMapClass
/-- Turn an element of a type `F` satisfying `AlgHomClass F α β` into an actual
`AlgHom`. This is declared as the default coercion from `F` to `α →+* β`. -/
@[coe]
def toAlgHom {F : Type*} [AlgHomClass F R A B] (f : F) : A →ₐ[R] B :=
def toAlgHom {F : Type*} [FunLike F A B] [AlgHomClass F R A B] (f : F) : A →ₐ[R] B :=
{ (f : A →+* B) with
toFun := f
commutes' := AlgHomClass.commutes f }

instance coeTC {F : Type*} [AlgHomClass F R A B] : CoeTC F (A →ₐ[R] B) :=
instance coeTC {F : Type*} [FunLike F A B] [AlgHomClass F R A B] : CoeTC F (A →ₐ[R] B) :=
⟨AlgHomClass.toAlgHom⟩
#align alg_hom_class.alg_hom.has_coe_t AlgHomClass.coeTC

Expand All @@ -100,13 +100,15 @@ variable [Algebra R A] [Algebra R B] [Algebra R C] [Algebra R D]
-- Porting note: we don't port specialized `CoeFun` instances if there is `DFunLike` instead
#noalign alg_hom.has_coe_to_fun

-- Porting note: This instance is moved.
instance algHomClass : AlgHomClass (A →ₐ[R] B) R A B where
instance funLike : FunLike (A →ₐ[R] B) A B where
coe f := f.toFun
coe_injective' f g h := by
rcases f with ⟨⟨⟨⟨_, _⟩, _⟩, _, _⟩, _⟩
rcases g with ⟨⟨⟨⟨_, _⟩, _⟩, _, _⟩, _⟩
congr

-- Porting note: This instance is moved.
instance algHomClass : AlgHomClass (A →ₐ[R] B) R A B where
map_add f := f.map_add'
map_zero f := f.map_zero'
map_mul f := f.map_mul'
Expand All @@ -121,7 +123,8 @@ def Simps.apply {R : Type u} {α : Type v} {β : Type w} [CommSemiring R]
initialize_simps_projections AlgHom (toFun → apply)

@[simp]
protected theorem coe_coe {F : Type*} [AlgHomClass F R A B] (f : F) : ⇑(f : A →ₐ[R] B) = f :=
protected theorem coe_coe {F : Type*} [FunLike F A B] [AlgHomClass F R A B] (f : F) :
⇑(f : A →ₐ[R] B) = f :=
rfl
#align alg_hom.coe_coe AlgHom.coe_coe

Expand Down
37 changes: 23 additions & 14 deletions Mathlib/Algebra/Algebra/NonUnitalHom.lean
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ attribute [nolint docBlame] NonUnitalAlgHom.toMulHom

/-- `NonUnitalAlgHomClass F R A B` asserts `F` is a type of bundled algebra homomorphisms
from `A` to `B`. -/
class NonUnitalAlgHomClass (F : Type*) (R : outParam (Type*)) (A : outParam (Type*))
(B : outParam (Type*)) [Monoid R] [NonUnitalNonAssocSemiring A] [NonUnitalNonAssocSemiring B]
[DistribMulAction R A] [DistribMulAction R B] extends DistribMulActionHomClass F R A B,
MulHomClass F A B
class NonUnitalAlgHomClass (F : Type*) (R A B : outParam Type*)
[Monoid R] [NonUnitalNonAssocSemiring A] [NonUnitalNonAssocSemiring B]
[DistribMulAction R A] [DistribMulAction R B] [FunLike F A B]
extends DistribMulActionHomClass F R A B, MulHomClass F A B : Prop
#align non_unital_alg_hom_class NonUnitalAlgHomClass

-- Porting note: commented out, not dangerous
Expand All @@ -80,30 +80,35 @@ namespace NonUnitalAlgHomClass
-- Porting note: Made following instance non-dangerous through [...] -> [...] replacement
-- See note [lower instance priority]
instance (priority := 100) toNonUnitalRingHomClass {F R A B : Type*}
[Monoid R] [NonUnitalNonAssocSemiring A] [DistribMulAction R A]
[NonUnitalNonAssocSemiring B] [DistribMulAction R B]
{_ : Monoid R} {_ : NonUnitalNonAssocSemiring A} [DistribMulAction R A]
{_ : NonUnitalNonAssocSemiring B} [DistribMulAction R B] [FunLike F A B]
[NonUnitalAlgHomClass F R A B] : NonUnitalRingHomClass F A B :=
{ ‹NonUnitalAlgHomClass F R A B› with coe := (⇑) }
{ ‹NonUnitalAlgHomClass F R A B› with }
#align non_unital_alg_hom_class.non_unital_alg_hom_class.to_non_unital_ring_hom_class NonUnitalAlgHomClass.toNonUnitalRingHomClass

variable [Semiring R] [NonUnitalNonAssocSemiring A] [Module R A]
[NonUnitalNonAssocSemiring B] [Module R B]

-- see Note [lower instance priority]
instance (priority := 100) {F : Type*} [NonUnitalAlgHomClass F R A B] : LinearMapClass F R A B :=
instance (priority := 100) {F R A B : Type*}
{_ : Semiring R} {_ : NonUnitalSemiring A} {_ : NonUnitalSemiring B}
[Module R A] [Module R B]
[FunLike F A B] [NonUnitalAlgHomClass F R A B] :
LinearMapClass F R A B :=
{ ‹NonUnitalAlgHomClass F R A B› with map_smulₛₗ := map_smul }

/-- Turn an element of a type `F` satisfying `NonUnitalAlgHomClass F R A B` into an actual
`NonUnitalAlgHom`. This is declared as the default coercion from `F` to `A →ₙₐ[R] B`. -/
@[coe]
def toNonUnitalAlgHom {F R A B : Type*} [Monoid R] [NonUnitalNonAssocSemiring A]
[DistribMulAction R A] [NonUnitalNonAssocSemiring B] [DistribMulAction R B]
[DistribMulAction R A] [NonUnitalNonAssocSemiring B] [DistribMulAction R B] [FunLike F A B]
[NonUnitalAlgHomClass F R A B] (f : F) : A →ₙₐ[R] B :=
{ (f : A →ₙ+* B) with
map_smul' := map_smul f }

instance {F R A B : Type*} [Monoid R] [NonUnitalNonAssocSemiring A] [DistribMulAction R A]
[NonUnitalNonAssocSemiring B] [DistribMulAction R B] [NonUnitalAlgHomClass F R A B] :
[NonUnitalNonAssocSemiring B] [DistribMulAction R B]
[FunLike F A B] [NonUnitalAlgHomClass F R A B] :
CoeTC F (A →ₙₐ[R] B) :=
⟨toNonUnitalAlgHom⟩

Expand Down Expand Up @@ -140,7 +145,7 @@ initialize_simps_projections NonUnitalAlgHom
(toDistribMulActionHom_toMulActionHom_toFun → apply, -toDistribMulActionHom)

@[simp]
protected theorem coe_coe {F : Type*} [NonUnitalAlgHomClass F R A B] (f : F) :
protected theorem coe_coe {F : Type*} [FunLike F A B] [NonUnitalAlgHomClass F R A B] (f : F) :
⇑(f : A →ₙₐ[R] B) = f :=
rfl
#align non_unital_alg_hom.coe_coe NonUnitalAlgHom.coe_coe
Expand All @@ -149,14 +154,17 @@ theorem coe_injective : @Function.Injective (A →ₙₐ[R] B) (A → B) (↑) :
rintro ⟨⟨⟨f, _⟩, _⟩, _⟩ ⟨⟨⟨g, _⟩, _⟩, _⟩ h; congr
#align non_unital_alg_hom.coe_injective NonUnitalAlgHom.coe_injective

instance : NonUnitalAlgHomClass (A →ₙₐ[R] B) R A B
instance : FunLike (A →ₙₐ[R] B) A B
where
coe f := f.toFun
coe_injective' := coe_injective
map_smul f := f.map_smul'

instance : NonUnitalAlgHomClass (A →ₙₐ[R] B) R A B
where
map_add f := f.map_add'
map_zero f := f.map_zero'
map_mul f := f.map_mul'
map_smul f := f.map_smul'

@[ext]
theorem ext {f g : A →ₙₐ[R] B} (h : ∀ x, f x = g x) : f = g :=
Expand Down Expand Up @@ -434,7 +442,8 @@ variable {R A B} [CommSemiring R] [Semiring A] [Semiring B] [Algebra R A]
[Algebra R B]

-- see Note [lower instance priority]
instance (priority := 100) [AlgHomClass F R A B] : NonUnitalAlgHomClass F R A B :=
instance (priority := 100) [FunLike F A B] [AlgHomClass F R A B] :
NonUnitalAlgHomClass F R A B :=
{ ‹AlgHomClass F R A B› with map_smul := map_smul }

/-- A unital morphism of algebras is a `NonUnitalAlgHom`. -/
Expand Down
12 changes: 6 additions & 6 deletions Mathlib/Algebra/Algebra/NonUnitalSubalgebra.lean
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ we define it as a `LinearEquiv` to avoid type equalities. -/
def toSubmoduleEquiv (S : NonUnitalSubalgebra R A) : S.toSubmodule ≃ₗ[R] S :=
LinearEquiv.ofEq _ _ rfl

variable [NonUnitalAlgHomClass F R A B]
variable [FunLike F A B] [NonUnitalAlgHomClass F R A B]

/-- Transport a non-unital subalgebra via an algebra homomorphism. -/
def map (f : F) (S : NonUnitalSubalgebra R A) : NonUnitalSubalgebra R B :=
Expand Down Expand Up @@ -422,7 +422,7 @@ namespace NonUnitalAlgHom
variable {F : Type v'} {R' : Type u'} {R : Type u} {A : Type v} {B : Type w} {C : Type w'}
variable [CommSemiring R]
variable [NonUnitalNonAssocSemiring A] [Module R A] [NonUnitalNonAssocSemiring B] [Module R B]
variable [NonUnitalNonAssocSemiring C] [Module R C] [NonUnitalAlgHomClass F R A B]
variable [NonUnitalNonAssocSemiring C] [Module R C] [FunLike F A B] [NonUnitalAlgHomClass F R A B]

/-- Range of an `NonUnitalAlgHom` as a non-unital subalgebra. -/
protected def range (φ : F) : NonUnitalSubalgebra R B where
Expand Down Expand Up @@ -492,14 +492,14 @@ def equalizer (ϕ ψ : F) : NonUnitalSubalgebra R A

@[simp]
theorem mem_equalizer (φ ψ : F) (x : A) :
x ∈ @NonUnitalAlgHom.equalizer F R A B _ _ _ _ _ _ φ ψ ↔ φ x = ψ x :=
x ∈ NonUnitalAlgHom.equalizer φ ψ ↔ φ x = ψ x :=
Iff.rfl

/-- The range of a morphism of algebras is a fintype, if the domain is a fintype.
Note that this instance can cause a diamond with `Subtype.fintype` if `B` is also a fintype. -/
instance fintypeRange [Fintype A] [DecidableEq B] (φ : F) :
Fintype (@NonUnitalAlgHom.range F R A B _ _ _ _ _ _ φ) :=
Fintype (NonUnitalAlgHom.range φ) :=
Set.fintypeRange φ

end NonUnitalAlgHom
Expand All @@ -510,7 +510,7 @@ variable {F : Type*} (R : Type u) {A : Type v} {B : Type w}
variable [CommSemiring R]
variable [NonUnitalNonAssocSemiring A] [Module R A] [IsScalarTower R A A] [SMulCommClass R A A]
variable [NonUnitalNonAssocSemiring B] [Module R B] [IsScalarTower R B B] [SMulCommClass R B B]
variable [NonUnitalAlgHomClass F R A B]
variable [FunLike F A B] [NonUnitalAlgHomClass F R A B]

/-- The minimal non-unital subalgebra that includes `s`. -/
def adjoin (s : Set A) : NonUnitalSubalgebra R A :=
Expand Down Expand Up @@ -671,7 +671,7 @@ theorem mul_mem_sup {S T : NonUnitalSubalgebra R A} {x y : A} (hx : x ∈ S) (hy

theorem map_sup (f : F) (S T : NonUnitalSubalgebra R A) :
((S ⊔ T).map f : NonUnitalSubalgebra R B) = S.map f ⊔ T.map f :=
(@NonUnitalSubalgebra.gc_map_comap F R A B _ _ _ _ _ _ f).l_sup
(NonUnitalSubalgebra.gc_map_comap f).l_sup

@[simp, norm_cast]
theorem coe_inf (S T : NonUnitalSubalgebra R A) : (↑(S ⊓ T) : Set A) = (S : Set A) ∩ T :=
Expand Down
12 changes: 7 additions & 5 deletions Mathlib/Algebra/Algebra/Operations.lean
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ theorem le_one_toAddSubmonoid : 1 ≤ (1 : Submodule R A).toAddSubmonoid := by
#align submodule.le_one_to_add_submonoid Submodule.le_one_toAddSubmonoid

theorem algebraMap_mem (r : R) : algebraMap R A r ∈ (1 : Submodule R A) :=
LinearMap.mem_range_self _ _
LinearMap.mem_range_self (Algebra.linearMap R A) _
#align submodule.algebra_map_mem Submodule.algebraMap_mem

@[simp]
Expand Down Expand Up @@ -588,7 +588,8 @@ theorem map_unop_pow (n : ℕ) (M : Submodule R Aᵐᵒᵖ) :
on either side). -/
@[simps]
def span.ringHom : SetSemiring A →+* Submodule R A where
toFun s := Submodule.span R (SetSemiring.down s)
-- Note: the hint `(α := A)` is new in #8386
toFun s := Submodule.span R (SetSemiring.down (α := A) s)
map_zero' := span_empty
map_one' := one_eq_span.symm
map_add' := span_union
Expand Down Expand Up @@ -659,7 +660,8 @@ variable (R A)
/-- R-submodules of the R-algebra A are a module over `Set A`. -/
instance moduleSet : Module (SetSemiring A) (Submodule R A) where
-- porting note: have to unfold both `HSMul.hSMul` and `SMul.smul`
smul s P := span R (SetSemiring.down s) * P
-- Note: the hint `(α := A)` is new in #8386
smul s P := span R (SetSemiring.down (α := A) s) * P
smul_add _ _ _ := mul_add _ _ _
add_smul s t P := by
simp_rw [HSMul.hSMul, SetSemiring.down_add, span_union, sup_mul, add_eq_sup]
Expand All @@ -675,12 +677,12 @@ instance moduleSet : Module (SetSemiring A) (Submodule R A) where
variable {R A}

theorem smul_def (s : SetSemiring A) (P : Submodule R A) :
s • P = span R (SetSemiring.down s) * P :=
s • P = span R (SetSemiring.down (α := A) s) * P :=
rfl
#align submodule.smul_def Submodule.smul_def

theorem smul_le_smul {s t : SetSemiring A} {M N : Submodule R A}
(h₁ : SetSemiring.down s ⊆ SetSemiring.down t)
(h₁ : SetSemiring.down (α := A) s ⊆ SetSemiring.down (α := A) t)
(h₂ : M ≤ N) : s • M ≤ t • N :=
mul_le_mul (span_mono h₁) h₂
#align submodule.smul_le_smul Submodule.smul_le_smul
Expand Down
Loading

0 comments on commit c6a73d4

Please sign in to comment.