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

Commit da132ec

Browse files
feat(*): define subobject classes from submonoid up to subfield (#11750)
The next part of my big refactoring plans: subobject classes in the same style as morphism classes. This PR introduces the following subclasses of `set_like`: * `one_mem_class`, `zero_mem_class`, `mul_mem_class`, `add_mem_class`, `inv_mem_class`, `neg_mem_class` * `submonoid_class`, `add_submonoid_class` * `subgroup_class`, `add_subgroup_class` * `subsemiring_class`, `subring_class`, `subfield_class` The main purpose of this refactor is that we can replace the wide variety of lemmas like `{add_submonoid,add_subgroup,subring,subfield,submodule,subwhatever}.{prod,sum}_mem` with a single `prod_mem` lemma that is generic over all types `B` that extend `submonoid`: ```lean @[to_additive] lemma prod_mem {M : Type*} [comm_monoid M] [set_like B M] [submonoid_class B M] {ι : Type*} {t : finset ι} {f : ι → M} (h : ∀c ∈ t, f c ∈ S) : ∏ c in t, f c ∈ S ``` ## API changes * When you extend a `struct subobject`, make sure to create a corresponding `subobject_class` instance. ## Upcoming PRs This PR splits out the first part of #11545, namely defining the subobject classes. I am planning these follow-up PRs for further parts of #11545: - [ ] make the subobject consistently implicit in `{add,mul}_mem` #11758 - [ ] remove duplicate instances like `subgroup.to_group` (replaced by the `subgroup_class.to_subgroup` instances that are added by this PR) #11759 - [ ] further deduplication such as `finsupp_sum_mem` ## Subclassing `set_like` Contrary to mathlib's typical subclass pattern, we don't extend `set_like`, but take a `set_like` instance parameter: ```lean class one_mem_class (S : Type*) (M : out_param $ Type*) [has_one M] [set_like S M] := (one_mem : ∀ (s : S), (1 : M) ∈ s) ``` instead of: ```lean class one_mem_class (S : Type*) (M : out_param $ Type*) [has_one M] extends set_like S M := (one_mem : ∀ (s : S), (1 : M) ∈ s) ``` The main reason is that this avoids some big defeq checks when typechecking e.g. `x * y : s`, where `s : S` and `[comm_group G] [subgroup_class S G]`. Namely, the type `coe_sort s` could be given by `subgroup_class → @@submonoid_class _ _ (comm_group.to_group.to_monoid) → set_like → has_coe_to_sort` or by `subgroup_class → @@submonoid_class _ _ (comm_group.to_comm_monoid.to_monoid) → set_like → has_coe_to_sort`. When checking that `has_mul` on the first type is the same as `has_mul` on the second type, those two inheritance paths are unified many times over ([sometimes exponentially many](https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/Why.20is.20.60int.2Ecast_abs.60.20so.20slow.3F/near/266945077)). So it's important to keep the size of types small, and therefore we avoid `extends`-based inheritance. ## Defeq fixes Adding instances like `subgroup_class.to_group` means that there are now two (defeq) group instances for `subgroup`. This makes some code more fragile, until we can replace `subgroup.to_group` with its more generic form in a follow-up PR. Especially when taking subgroups of subgroups I needed to help the elaborator in a few places. These should be minimally invasive for other uses of the code. ## Timeout fixes Some of the leaf files started timing out, so I made a couple of fixes. Generally these can be classed as: * `squeeze_simps` * Give inheritance `subX_class S M` → `X s` (where `s : S`) a lower prority than `Y s` → `X s` so that `subY_class S M` → `Y s` → `X s` is preferred over `subY_class S M` → `subX_class S M` → `X s`. This addresses slow unifications when `x : s`, `s` is a submonoid of `t`, which is itself a subgroup of `G`: existing code expects to go `subgroup → group → monoid`, which got changed to `subgroup_class → submonoid_class → monoid`; when this kind of unification issue appears in your type this results in slow unification. By tweaking the priorities, we help the elaborator find our preferred instance, avoiding the big defeq checks. (The real fix should of course be to fix the unifier so it doesn't become exponential in these kinds of cases.) * Split a long proof with duplication into smaller parts. This was basically my last resort. I decided to bump the limit for the `fails_quickly` linter for `measure_theory.Lp_meas.complete_space`, which apparently just barely goes over this limit now. The time difference was about 10%-20% for that specific instance. Co-authored-by: Anne Baanen <Vierkantor@users.noreply.github.com> Co-authored-by: Riccardo Brasca <riccardo.brasca@gmail.com>
1 parent 220f71b commit da132ec

File tree

23 files changed

+745
-55
lines changed

23 files changed

+745
-55
lines changed

src/algebra/algebra/subalgebra/basic.lean

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,14 @@ variables [semiring A] [algebra R A] [semiring B] [algebra R B] [semiring C] [al
3737
include R
3838

3939
instance : set_like (subalgebra R A) A :=
40-
⟨subalgebra.carrier, λ p q h, by cases p; cases q; congr'⟩
40+
{ coe := subalgebra.carrier,
41+
coe_injective' := λ p q h, by cases p; cases q; congr' }
42+
43+
instance : subsemiring_class (subalgebra R A) A :=
44+
{ add_mem := add_mem',
45+
mul_mem := mul_mem',
46+
one_mem := one_mem',
47+
zero_mem := zero_mem' }
4148

4249
@[simp]
4350
lemma mem_carrier {s : subalgebra R A} {x : A} : x ∈ s.carrier ↔ x ∈ s := iff.rfl
@@ -101,6 +108,10 @@ S.to_subsemiring.zero_mem
101108
theorem add_mem {x y : A} (hx : x ∈ S) (hy : y ∈ S) : x + y ∈ S :=
102109
S.to_subsemiring.add_mem hx hy
103110

111+
instance {R A : Type*} [comm_ring R] [ring A] [algebra R A] : subring_class (subalgebra R A) A :=
112+
{ neg_mem := λ S x hx, neg_one_smul R x ▸ S.smul_mem hx _,
113+
.. subalgebra.subsemiring_class }
114+
104115
theorem neg_mem {R : Type u} {A : Type v} [comm_ring R] [ring A]
105116
[algebra R A] (S : subalgebra R A) {x : A} (hx : x ∈ S) : -x ∈ S :=
106117
neg_one_smul R x ▸ S.smul_mem hx _

src/algebra/lie/subalgebra.lean

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,20 @@ instance : has_zero (lie_subalgebra R L) :=
4949

5050
instance : inhabited (lie_subalgebra R L) := ⟨0
5151
instance : has_coe (lie_subalgebra R L) (submodule R L) := ⟨lie_subalgebra.to_submodule⟩
52-
instance : has_mem L (lie_subalgebra R L) := ⟨λ x L', x ∈ (L' : set L)⟩
5352

5453
namespace lie_subalgebra
5554

55+
open neg_mem_class
56+
57+
instance : set_like (lie_subalgebra R L) L :=
58+
{ coe := λ L', L',
59+
coe_injective' := λ L' L'' h, by { rcases L' with ⟨⟨⟩⟩, rcases L'' with ⟨⟨⟩⟩, congr' } }
60+
61+
instance : add_subgroup_class (lie_subalgebra R L) L :=
62+
{ add_mem := λ L', L'.add_mem',
63+
zero_mem := λ L', L'.zero_mem',
64+
neg_mem := λ L' x hx, show -x ∈ (L' : submodule R L), from neg_mem hx }
65+
5666
/-- A Lie subalgebra forms a new Lie ring. -/
5767
instance (L' : lie_subalgebra R L) : lie_ring L' :=
5868
{ bracket := λ x y, ⟨⁅x.val, y.val⁆, L'.lie_mem' x.property y.property⟩,
@@ -119,10 +129,10 @@ lemma coe_zero_iff_zero (x : L') : (x : L) = 0 ↔ x = 0 := (ext_iff L' x 0).sym
119129

120130
@[ext] lemma ext (L₁' L₂' : lie_subalgebra R L) (h : ∀ x, x ∈ L₁' ↔ x ∈ L₂') :
121131
L₁' = L₂' :=
122-
by { cases L₁', cases L₂', simp only [], ext x, exact h x, }
132+
set_like.ext h
123133

124134
lemma ext_iff' (L₁' L₂' : lie_subalgebra R L) : L₁' = L₂' ↔ ∀ x, x ∈ L₁' ↔ x ∈ L₂' :=
125-
⟨λ h x, by rw h, ext L₁' L₂'⟩
135+
set_like.ext_iff
126136

127137
@[simp] lemma mk_coe (S : set L) (h₁ h₂ h₃ h₄) :
128138
((⟨⟨S, h₁, h₂, h₃⟩, h₄⟩ : lie_subalgebra R L) : set L) = S := rfl
@@ -132,12 +142,10 @@ lemma ext_iff' (L₁' L₂' : lie_subalgebra R L) : L₁' = L₂' ↔ ∀ x, x
132142
by { cases p, refl, }
133143

134144
lemma coe_injective : function.injective (coe : lie_subalgebra R L → set L) :=
135-
by { rintro ⟨⟨⟩⟩ ⟨⟨⟩⟩ h, congr' }
136-
137-
instance : set_like (lie_subalgebra R L) L := ⟨coe, coe_injective⟩
145+
set_like.coe_injective
138146

139147
@[norm_cast] theorem coe_set_eq (L₁' L₂' : lie_subalgebra R L) :
140-
(L₁' : set L) = L₂' ↔ L₁' = L₂' := coe_injective.eq_iff
148+
(L₁' : set L) = L₂' ↔ L₁' = L₂' := set_like.coe_set_eq
141149

142150
lemma to_submodule_injective :
143151
function.injective (coe : lie_subalgebra R L → submodule R L) :=
@@ -542,8 +550,8 @@ variables [comm_ring R] [lie_ring L₁] [lie_ring L₂] [lie_algebra R L₁] [li
542550
/-- An injective Lie algebra morphism is an equivalence onto its range. -/
543551
noncomputable def of_injective (f : L₁ →ₗ⁅R⁆ L₂) (h : function.injective f) :
544552
L₁ ≃ₗ⁅R⁆ f.range :=
545-
{ map_lie' := λ x y, by { apply set_coe.ext, simpa, },
546-
..(linear_equiv.of_injective ↑f $ by rwa [lie_hom.coe_to_linear_map])}
553+
{ map_lie' := λ x y, by { apply set_coe.ext, simpa },
554+
.. linear_equiv.of_injective (f : L₁ →ₗ[R] L₂) $ by rwa [lie_hom.coe_to_linear_map] }
547555

548556
@[simp] lemma of_injective_apply (f : L₁ →ₗ⁅R⁆ L₂) (h : function.injective f) (x : L₁) :
549557
↑(of_injective f h x) = f x := rfl

src/algebra/lie/submodule.lean

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,17 @@ namespace lie_submodule
4949

5050
variables {R L M} (N N' : lie_submodule R L M)
5151

52+
open neg_mem_class
53+
5254
instance : set_like (lie_submodule R L M) M :=
5355
{ coe := carrier,
5456
coe_injective' := λ N O h, by cases N; cases O; congr' }
5557

58+
instance : add_subgroup_class (lie_submodule R L M) M :=
59+
{ add_mem := λ N, N.add_mem',
60+
zero_mem := λ N, N.zero_mem',
61+
neg_mem := λ N x hx, show -x ∈ N.to_submodule, from neg_mem hx }
62+
5663
/-- The zero module is a Lie submodule of any Lie module. -/
5764
instance : has_zero (lie_submodule R L M) :=
5865
⟨{ lie_mem := λ x m h, by { rw ((submodule.mem_bot R).1 h), apply lie_zero, },

src/algebra/module/submodule.lean

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,12 @@ namespace submodule
4747
variables [semiring R] [add_comm_monoid M] [module R M]
4848

4949
instance : set_like (submodule R M) M :=
50-
⟨submodule.carrier, λ p q h, by cases p; cases q; congr'⟩
50+
{ coe := submodule.carrier,
51+
coe_injective' := λ p q h, by cases p; cases q; congr' }
52+
53+
instance : add_submonoid_class (submodule R M) M :=
54+
{ zero_mem := zero_mem',
55+
add_mem := add_mem' }
5156

5257
@[simp] theorem mem_to_add_submonoid (p : submodule R M) (x : M) : x ∈ p.to_add_submonoid ↔ x ∈ p :=
5358
iff.rfl
@@ -282,7 +287,11 @@ variables {module_M : module R M}
282287
variables (p p' : submodule R M)
283288
variables {r : R} {x y : M}
284289

285-
lemma neg_mem (hx : x ∈ p) : -x ∈ p := p.to_sub_mul_action.neg_mem hx
290+
instance [module R M] : add_subgroup_class (submodule R M) M :=
291+
{ neg_mem := λ p x, p.to_sub_mul_action.neg_mem,
292+
.. submodule.add_submonoid_class }
293+
294+
lemma neg_mem (hx : x ∈ p) : -x ∈ p := neg_mem_class.neg_mem hx
286295

287296
/-- Reinterpret a submodule as an additive subgroup. -/
288297
def to_add_subgroup : add_subgroup M :=

src/analysis/inner_product_space/l2_space.lean

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,6 @@ end
224224
protected lemma range_linear_isometry [Π i, complete_space (G i)] :
225225
hV.linear_isometry.to_linear_map.range = (⨆ i, (V i).to_linear_map.range).topological_closure :=
226226
begin
227-
classical,
228227
refine le_antisymm _ _,
229228
{ rintros x ⟨f, rfl⟩,
230229
refine mem_closure_of_tendsto (hV.has_sum_linear_isometry f) (eventually_of_forall _),
@@ -237,7 +236,7 @@ begin
237236
{ refine supr_le _,
238237
rintros i x ⟨x, rfl⟩,
239238
use lp.single 2 i x,
240-
convert hV.linear_isometry_apply_single _ },
239+
exact hV.linear_isometry_apply_single x },
241240
exact hV.linear_isometry.isometry.uniform_inducing.is_complete_range.is_closed }
242241
end
243242

src/field_theory/galois.lean

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ lemma alg_equiv.transfer_galois (f : E ≃ₐ[F] E') : is_galois F E ↔ is_galo
150150
⟨λ h, by exactI is_galois.of_alg_equiv f, λ h, by exactI is_galois.of_alg_equiv f.symm⟩
151151

152152
lemma is_galois_iff_is_galois_top : is_galois F (⊤ : intermediate_field F E) ↔ is_galois F E :=
153-
(intermediate_field.top_equiv).transfer_galois
153+
(intermediate_field.top_equiv : (⊤ : intermediate_field F E) ≃ₐ[F] E).transfer_galois
154154

155155
instance is_galois_bot : is_galois F (⊥ : intermediate_field F E) :=
156156
(intermediate_field.bot_equiv F E).transfer_galois.mpr (is_galois.self F)
@@ -401,7 +401,8 @@ begin
401401
simp only [P] at *,
402402
rw [of_separable_splitting_field_aux hp K (multiset.mem_to_finset.mp hx),
403403
hK, finrank_mul_finrank],
404-
exact (linear_equiv.finrank_eq (intermediate_field.lift2_alg_equiv K⟮x⟯).to_linear_equiv).symm,
404+
symmetry,
405+
exact linear_equiv.finrank_eq (alg_equiv.to_linear_equiv (intermediate_field.lift2_alg_equiv _))
405406
end
406407

407408
/--Equivalent characterizations of a Galois extension of finite degree-/

src/field_theory/intermediate_field.lean

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ def to_subfield : subfield L := { ..S.to_subalgebra, ..S }
6161
instance : set_like (intermediate_field K L) L :=
6262
⟨λ S, S.to_subalgebra.carrier, by { rintros ⟨⟨⟩⟩ ⟨⟨⟩⟩ ⟨h⟩, congr, }⟩
6363

64+
instance : subfield_class (intermediate_field K L) L :=
65+
{ add_mem := λ s, s.add_mem',
66+
zero_mem := λ s, s.zero_mem',
67+
neg_mem := neg_mem',
68+
mul_mem := λ s, s.mul_mem',
69+
one_mem := λ s, s.one_mem',
70+
inv_mem := inv_mem' }
71+
6472
@[simp]
6573
lemma mem_carrier {s : intermediate_field K L} {x : L} : x ∈ s.carrier ↔ x ∈ s := iff.rfl
6674

src/field_theory/subfield.lean

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,43 @@ universes u v w
6363

6464
variables {K : Type u} {L : Type v} {M : Type w} [field K] [field L] [field M]
6565

66+
/-- `subfield_class S K` states `S` is a type of subsets `s ⊆ K` closed under field operations. -/
67+
class subfield_class (S : Type*) (K : out_param $ Type*) [field K] [set_like S K]
68+
extends subring_class S K, inv_mem_class S K.
69+
70+
namespace subfield_class
71+
72+
variables (S : Type*) [set_like S K] [h : subfield_class S K]
73+
include h
74+
75+
/-- A subfield contains `1`, products and inverses.
76+
77+
Be assured that we're not actually proving that subfields are subgroups:
78+
`subgroup_class` is really an abbreviation of `subgroup_with_or_without_zero_class`.
79+
-/
80+
@[priority 100] -- See note [lower instance priority]
81+
instance subfield_class.to_subgroup_class : subgroup_class S K := { .. h }
82+
83+
/-- A subfield inherits a field structure -/
84+
@[priority 75] -- Prefer subclasses of `field` over subclasses of `subfield_class`.
85+
instance to_field (s : S) : field s :=
86+
subtype.coe_injective.field (coe : s → K)
87+
rfl rfl (λ _ _, rfl) (λ _ _, rfl) (λ _, rfl) (λ _ _, rfl) (λ _, rfl) (λ _ _, rfl) (λ _ _, rfl)
88+
(λ _ _, rfl) (λ _ _, rfl) (λ _ _, rfl)
89+
90+
omit h
91+
92+
/-- A subfield of a `linear_ordered_field` is a `linear_ordered_field`. -/
93+
@[priority 75] -- Prefer subclasses of `field` over subclasses of `subfield_class`.
94+
instance to_linear_ordered_field {K} [linear_ordered_field K] [set_like S K]
95+
[subfield_class S K] (s : S) :
96+
linear_ordered_field s :=
97+
subtype.coe_injective.linear_ordered_field coe
98+
rfl rfl (λ _ _, rfl) (λ _ _, rfl) (λ _, rfl) (λ _ _, rfl) (λ _, rfl) (λ _ _, rfl) (λ _ _, rfl)
99+
(λ _ _, rfl) (λ _ _, rfl) (λ _ _, rfl)
100+
101+
end subfield_class
102+
66103
set_option old_structure_cmd true
67104

68105
/-- `subfield R` is the type of subfields of `R`. A subfield of `R` is a subset `s` that is a
@@ -84,10 +121,17 @@ def to_add_subgroup (s : subfield K) : add_subgroup K :=
84121
def to_submonoid (s : subfield K) : submonoid K :=
85122
{ ..s.to_subring.to_submonoid }
86123

87-
88124
instance : set_like (subfield K) K :=
89125
⟨subfield.carrier, λ p q h, by cases p; cases q; congr'⟩
90126

127+
instance : subfield_class (subfield K) K :=
128+
{ add_mem := add_mem',
129+
zero_mem := zero_mem',
130+
neg_mem := neg_mem',
131+
mul_mem := mul_mem',
132+
one_mem := one_mem',
133+
inv_mem := inv_mem' }
134+
91135
@[simp]
92136
lemma mem_carrier {s : subfield K} {x : K} : x ∈ s.carrier ↔ x ∈ s := iff.rfl
93137

0 commit comments

Comments
 (0)