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

Commit b353176

Browse files
ericrbgeric-wieserriccardobrasca
committed
feat(field_theory/splitting_field): fix the diamond (#18857)
This re-implements how instances for `splitting_field` in such a way that we can now avoid diamonds with the N, Z and Q-actions. This makes a lot more instances safe, which is good for e.g. flt-regular. Many thanks to @Vierkantor for many of the ideas and all the `distrib_smul` PRs that were needed for this. Co-authored-by: Eric Wieser <wieser.eric@gmail.com> Co-authored-by: Riccardo Brasca <riccardo.brasca@gmail.com>
1 parent 3b88f40 commit b353176

3 files changed

Lines changed: 254 additions & 80 deletions

File tree

src/field_theory/splitting_field.lean

Lines changed: 245 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Copyright (c) 2018 Chris Hughes. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Chris Hughes
55
-/
6+
import algebra.char_p.algebra
67
import field_theory.intermediate_field
78
import ring_theory.adjoin.field
89

@@ -109,46 +110,234 @@ namespace splitting_field_aux
109110
theorem succ (n : ℕ) (f : K[X]) :
110111
splitting_field_aux (n+1) f = splitting_field_aux n f.remove_factor := rfl
111112

112-
instance field (n : ℕ) : Π {K : Type u} [field K], by exactI
113-
Π {f : K[X]}, field (splitting_field_aux n f) :=
114-
nat.rec_on n (λ K _ _, ‹field K›) $ λ n ih K _ f, ih
113+
section lift_instances
115114

116-
instance inhabited {n : ℕ} {f : K[X]} :
117-
inhabited (splitting_field_aux n f) := ⟨37
115+
/-! ### Instances on `splitting_field_aux`
118116
119-
/-
120-
Note that the recursive nature of this definition and `splitting_field_aux.field` creates
121-
non-definitionally-equal diamonds in the `ℕ`- and `ℤ`- actions.
122-
```lean
123-
example (n : ℕ) {K : Type u} [field K] {f : K[X]} (hfn : f.nat_degree = n) :
124-
(add_comm_monoid.nat_module : module ℕ (splitting_field_aux n f hfn)) =
125-
@algebra.to_module _ _ _ _ (splitting_field_aux.algebra n _ hfn) :=
126-
rfl -- fails
127-
```
128-
It's not immediately clear whether this _can_ be fixed; the failure is much the same as the reason
129-
that the following fails:
130-
```lean
131-
def cases_twice {α} (a₀ aₙ : α) : ℕ → α × α
132-
| 0 := (a₀, a₀)
133-
| (n + 1) := (aₙ, aₙ)
134-
135-
example (x : ℕ) {α} (a₀ aₙ : α) : (cases_twice a₀ aₙ x).1 = (cases_twice a₀ aₙ x).2 := rfl -- fails
136-
```
137-
We don't really care at this point because this is an implementation detail (which is why this is
138-
not a docstring), but we do in `splitting_field.algebra'` below. -/
139-
instance algebra (n : ℕ) : Π (R : Type*) {K : Type u} [comm_semiring R] [field K],
140-
by exactI Π [algebra R K] {f : K[X]},
141-
algebra R (splitting_field_aux n f) :=
142-
nat.rec_on n (λ R K _ _ _ _, by exactI ‹algebra R K›) $
143-
λ n ih R K _ _ _ f, by exactI ih R
117+
In order to avoid diamond issues, we have to be careful to define each data field of algebraic
118+
instances on `splitting_field_aux` by recursion, rather than defining the whole structure by
119+
recursion at once.
120+
121+
The important detail is that the `smul` instances can be lifted _before_ we create the algebraic
122+
instances; if we do not do this, this creates a mutual dependence on both on each other, and it
123+
is impossible to untangle this mess. In order to do this, we need that these `smul` instances
124+
are distributive in the sense of `distrib_smul`, which is weak enough to be guaranteed at this
125+
stage. This is sufficient to lift an action to `adjoin_root f` (remember that this is a quotient,
126+
so these conditions are equivalent to well-definedness), which is all we need.
127+
-/
128+
129+
/-- Splitting fields have a zero. -/
130+
protected def zero (n : ℕ) : Π {K : Type u} [field K], by exactI Π {f : K[X]},
131+
splitting_field_aux n f :=
132+
nat.rec_on n (λ K fK f, by exactI @has_zero.zero K _) (λ n ih K fK f, ih)
133+
134+
/-- Splitting fields have an addition. -/
135+
protected def add (n : ℕ) : Π {K : Type u} [field K], by exactI Π {f : K[X]},
136+
splitting_field_aux n f → splitting_field_aux n f → splitting_field_aux n f :=
137+
nat.rec_on n (λ K fK f, by exactI @has_add.add K _) (λ n ih K fK f, ih)
138+
139+
/-- Splitting fields inherit scalar multiplication. -/
140+
protected def smul (n : ℕ) : Π (α : Type*) {K : Type u} [field K],
141+
by exactI Π [distrib_smul α K],
142+
by exactI Π [is_scalar_tower α K K] {f : K[X]},
143+
α → splitting_field_aux n f → splitting_field_aux n f :=
144+
nat.rec_on n
145+
(λ α K fK ds ist f, by exactI @has_smul.smul _ K _)
146+
(λ n ih α K fK ds ist f, by exactI ih α)
147+
148+
instance has_smul (α : Type*) (n : ℕ) {K : Type u} [field K] [distrib_smul α K]
149+
[is_scalar_tower α K K] {f : K[X]} :
150+
has_smul α (splitting_field_aux n f) :=
151+
⟨splitting_field_aux.smul n α⟩
144152

145153
instance is_scalar_tower (n : ℕ) : Π (R₁ R₂ : Type*) {K : Type u}
146-
[comm_semiring R₁] [comm_semiring R₂] [has_smul R₁ R₂] [field K],
147-
by exactI Π [algebra R₁ K] [algebra R₂ K],
148-
by exactI Π [is_scalar_tower R₁ R₂ K] {f : K[X]},
149-
is_scalar_tower R₁ R₂ (splitting_field_aux n f) :=
150-
nat.rec_on n (λ R₁ R₂ K _ _ _ _ _ _ _ _, by exactI ‹is_scalar_tower R₁ R₂ K›) $
151-
λ n ih R₁ R₂ K _ _ _ _ _ _ _ f, by exactI ih R₁ R₂
154+
[has_smul R₁ R₂] [field K],
155+
by exactI Π [distrib_smul R₂ K] [distrib_smul R₁ K],
156+
by exactI Π [is_scalar_tower R₁ K K] [is_scalar_tower R₂ K K] [is_scalar_tower R₁ R₂ K]
157+
{f : K[X]}, by exactI is_scalar_tower R₁ R₂ (splitting_field_aux n f) :=
158+
nat.rec_on n (λ R₁ R₂ K _ _ hs₂ hs₁ _ _ h f,
159+
begin
160+
rcases hs₁ with @⟨@⟨⟨hs₁⟩,_⟩,_⟩,
161+
rcases hs₂ with @⟨@⟨⟨hs₂⟩,_⟩,_⟩,
162+
exact h,
163+
end) $ λ n ih R₁ R₂ K _ _ _ _ _ _ _ f, by exactI ih R₁ R₂
164+
165+
/-- Splitting fields have a negation. -/
166+
protected def neg (n : ℕ) : Π {K : Type u} [field K], by exactI Π {f : K[X]},
167+
splitting_field_aux n f → splitting_field_aux n f :=
168+
nat.rec_on n (λ K fK f, by exactI @has_neg.neg K _) (λ n ih K fK f, ih)
169+
170+
/-- Splitting fields have subtraction. -/
171+
protected def sub (n : ℕ) : Π {K : Type u} [field K], by exactI Π {f : K[X]},
172+
splitting_field_aux n f → splitting_field_aux n f → splitting_field_aux n f :=
173+
nat.rec_on n (λ K fK f, by exactI @has_sub.sub K _) (λ n ih K fK f, ih)
174+
175+
/-- Splitting fields have a one. -/
176+
protected def one (n : ℕ) : Π {K : Type u} [field K], by exactI Π {f : K[X]},
177+
splitting_field_aux n f :=
178+
nat.rec_on n (λ K fK f, by exactI @has_one.one K _) (λ n ih K fK f, ih)
179+
180+
/-- Splitting fields have a multiplication. -/
181+
protected def mul (n : ℕ) : Π {K : Type u} [field K], by exactI Π {f : K[X]},
182+
splitting_field_aux n f → splitting_field_aux n f → splitting_field_aux n f :=
183+
nat.rec_on n (λ K fK f, by exactI @has_mul.mul K _) (λ n ih K fK f, ih)
184+
185+
/-- Splitting fields have a power operation. -/
186+
protected def npow (n : ℕ) : Π {K : Type u} [field K], by exactI Π {f : K[X]},
187+
ℕ → splitting_field_aux n f → splitting_field_aux n f :=
188+
nat.rec_on n (λ K fK f n x, by exactI @has_pow.pow K _ _ x n) (λ n ih K fK f, ih)
189+
190+
/-- Splitting fields have an injection from the base field. -/
191+
protected def mk (n : ℕ) : Π {K : Type u} [field K],
192+
by exactI Π {f : K[X]}, K → splitting_field_aux n f :=
193+
nat.rec_on n (λ K fK f, id) (λ n ih K fK f, by exactI ih ∘ coe)
194+
-- note that `coe` goes from `K → adjoin_root f`, and then `ih` lifts to the full splitting field
195+
-- (as we generalise over all fields in this recursion!)
196+
197+
/-- Splitting fields have an inverse. -/
198+
protected def inv (n : ℕ) : Π {K : Type u} [field K], by exactI Π {f : K[X]},
199+
splitting_field_aux n f → splitting_field_aux n f :=
200+
nat.rec_on n (λ K fK f, by exactI @has_inv.inv K _) (λ n ih K fK f, ih)
201+
202+
/-- Splitting fields have a division. -/
203+
protected def div (n : ℕ) : Π {K : Type u} [field K], by exactI Π {f : K[X]},
204+
splitting_field_aux n f → splitting_field_aux n f → splitting_field_aux n f :=
205+
nat.rec_on n (λ K fK f, by exactI @has_div.div K _) (λ n ih K fK f, ih)
206+
207+
/-- Splitting fields have powers by integers. -/
208+
protected def zpow (n : ℕ) : Π {K : Type u} [field K], by exactI Π {f : K[X]},
209+
ℤ → splitting_field_aux n f → splitting_field_aux n f :=
210+
nat.rec_on n (λ K fK f n x, by exactI @has_pow.pow K _ _ x n) (λ n ih K fK f, ih)
211+
212+
-- I'm not sure why these two lemmas break, but inlining them seems to not work.
213+
private lemma nsmul_zero (n : ℕ) : Π {K : Type u} [field K], by exactI Π {f : K[X]}
214+
(x : splitting_field_aux n f), (0 : ℕ) • x = splitting_field_aux.zero n :=
215+
nat.rec_on n (λ K fK f, by exactI zero_nsmul) (λ n ih K fK f, by exactI ih)
216+
217+
private lemma nsmul_succ (n : ℕ) : Π {K : Type u} [field K], by exactI Π {f : K[X]}
218+
(k : ℕ) (x : splitting_field_aux n f),
219+
(k + 1) • x = splitting_field_aux.add n x (k • x) :=
220+
nat.rec_on n (λ K fK f n x, by exactI succ_nsmul x n) (λ n ih K fK f, by exactI ih)
221+
222+
instance field (n : ℕ) {K : Type u} [field K] {f : K[X]} :
223+
field (splitting_field_aux n f) :=
224+
begin
225+
refine
226+
{ zero := splitting_field_aux.zero n,
227+
one := splitting_field_aux.one n,
228+
add := splitting_field_aux.add n,
229+
zero_add := have h : _ := @zero_add, _,
230+
add_zero := have h : _ := @add_zero, _,
231+
add_assoc := have h : _ := @add_assoc, _,
232+
add_comm := have h : _ := @add_comm, _,
233+
neg := splitting_field_aux.neg n,
234+
add_left_neg := have h : _ := @add_left_neg, _,
235+
sub := splitting_field_aux.sub n,
236+
sub_eq_add_neg := have h : _ := @sub_eq_add_neg, _,
237+
mul := splitting_field_aux.mul n,
238+
one_mul := have h : _ := @one_mul, _,
239+
mul_one := have h : _ := @mul_one, _,
240+
mul_assoc := have h : _ := @mul_assoc, _,
241+
left_distrib := have h : _ := @left_distrib, _,
242+
right_distrib := have h : _ := @right_distrib, _,
243+
mul_comm := have h : _ := @mul_comm, _,
244+
inv := splitting_field_aux.inv n,
245+
inv_zero := have h : _ := @inv_zero, _,
246+
div := splitting_field_aux.div n,
247+
div_eq_mul_inv := have h : _ := @div_eq_mul_inv, _,
248+
mul_inv_cancel := have h : _ := @mul_inv_cancel, _,
249+
exists_pair_ne := have h : _ := @exists_pair_ne, _,
250+
nat_cast := splitting_field_aux.mk n ∘ (coe : ℕ → K),
251+
nat_cast_zero := have h : _ := @comm_ring.nat_cast_zero, _,
252+
nat_cast_succ := have h : _ := @comm_ring.nat_cast_succ, _,
253+
nsmul := (•),
254+
nsmul_zero' := nsmul_zero n,
255+
nsmul_succ' := nsmul_succ n,
256+
int_cast := splitting_field_aux.mk n ∘ (coe : ℤ → K),
257+
int_cast_of_nat := have h : _ := @comm_ring.int_cast_of_nat, _,
258+
int_cast_neg_succ_of_nat := have h : _ := @comm_ring.int_cast_neg_succ_of_nat, _,
259+
zsmul := (•),
260+
zsmul_zero' := have h : _ := @subtraction_comm_monoid.zsmul_zero', _,
261+
zsmul_succ' := have h : _ := @subtraction_comm_monoid.zsmul_succ', _,
262+
zsmul_neg' := have h : _ := @subtraction_comm_monoid.zsmul_neg', _,
263+
rat_cast := splitting_field_aux.mk n ∘ (coe : ℚ → K),
264+
rat_cast_mk := have h : _ := @field.rat_cast_mk, _,
265+
qsmul := (•),
266+
qsmul_eq_mul' := have h : _ := @field.qsmul_eq_mul', _,
267+
npow := splitting_field_aux.npow n,
268+
npow_zero' := have h : _ := @comm_ring.npow_zero', _,
269+
npow_succ' := have h : _ := @comm_ring.npow_succ', _,
270+
zpow := splitting_field_aux.zpow n,
271+
zpow_zero' := have h : _ := @field.zpow_zero', _,
272+
zpow_succ' := have h : _ := @field.zpow_succ', _,
273+
zpow_neg' := have h : _ := @field.zpow_neg', _},
274+
all_goals {
275+
unfreezingI { induction n with n ih generalizing K },
276+
{ apply @h K },
277+
{ exact @ih _ _ _ } },
278+
end
279+
280+
instance inhabited {n : ℕ} {f : K[X]} :
281+
inhabited (splitting_field_aux n f) := ⟨37
282+
283+
/-- The injection from the base field as a ring homomorphism. -/
284+
@[simps] protected def mk_hom (n : ℕ) {K : Type u} [field K] {f : K[X]} :
285+
K →+* splitting_field_aux n f :=
286+
{ to_fun := splitting_field_aux.mk n,
287+
map_one' :=
288+
begin
289+
unfreezingI { induction n with k hk generalizing K },
290+
{ simp [splitting_field_aux.mk] },
291+
exact hk
292+
end,
293+
map_mul' :=
294+
begin
295+
unfreezingI { induction n with k hk generalizing K },
296+
{ simp [splitting_field_aux.mk] },
297+
intros x y,
298+
change (splitting_field_aux.mk k) ((adjoin_root.of f.factor) _) = _,
299+
rw [map_mul],
300+
exact hk _ _
301+
end,
302+
map_zero' :=
303+
begin
304+
unfreezingI { induction n with k hk generalizing K },
305+
{ simp [splitting_field_aux.mk] },
306+
change (splitting_field_aux.mk k) ((adjoin_root.of f.factor) 0) = _,
307+
rw [map_zero, hk],
308+
end,
309+
map_add' :=
310+
begin
311+
unfreezingI { induction n with k hk generalizing K },
312+
{ simp [splitting_field_aux.mk] },
313+
intros x y,
314+
change (splitting_field_aux.mk k) ((adjoin_root.of f.factor) _) = _,
315+
rw [map_add],
316+
exact hk _ _
317+
end }
318+
319+
instance algebra (n : ℕ) (R : Type*) {K : Type u} [comm_semiring R] [field K]
320+
[algebra R K] {f : K[X]} : algebra R (splitting_field_aux n f) :=
321+
{ to_fun := (splitting_field_aux.mk_hom n).comp (algebra_map R K),
322+
smul := (•),
323+
smul_def' :=
324+
begin
325+
unfreezingI { induction n with k hk generalizing K },
326+
{ exact algebra.smul_def },
327+
exact hk
328+
end,
329+
commutes' := λ a b, mul_comm _ _,
330+
.. (splitting_field_aux.mk_hom n).comp (algebra_map R K) }
331+
332+
/-- Because `splitting_field_aux` is defined by recursion, we have to make sure all instances
333+
on `splitting_field_aux` are defined by recursion within the fields. Otherwise, there will be
334+
instance diamonds such as the following: -/
335+
example (n : ℕ) {K : Type u} [field K] {f : K[X]} :
336+
(add_comm_monoid.nat_module : module ℕ (splitting_field_aux n f)) =
337+
@algebra.to_module _ _ _ _ (splitting_field_aux.algebra n _) :=
338+
rfl
339+
340+
end lift_instances
152341

153342
instance algebra''' {n : ℕ} {f : K[X]} :
154343
algebra (adjoin_root f.factor)
@@ -248,36 +437,32 @@ splitting_field_aux.field _
248437

249438
instance inhabited : inhabited (splitting_field f) := ⟨37
250439

251-
/-- This should be an instance globally, but it creates diamonds with the `ℕ`, `ℤ`, and `ℚ` algebras
252-
(via their `smul` and `to_fun` fields):
440+
instance algebra' {R} [comm_semiring R] [algebra R K] : algebra R (splitting_field f) :=
441+
splitting_field_aux.algebra _ _
253442

254-
```lean
255-
example :
256-
(algebra_nat : algebra ℕ (splitting_field f)) = splitting_field.algebra' f :=
257-
rfl -- fails
443+
instance : algebra K (splitting_field f) :=
444+
splitting_field_aux.algebra _ _
258445

259-
example :
260-
(algebra_int _ : algebra ℤ (splitting_field f)) = splitting_field.algebra' f :=
261-
rfl -- fails
446+
instance [char_zero K] : char_zero (splitting_field f) :=
447+
char_zero_of_injective_algebra_map ((algebra_map K _).injective)
262448

263-
example [char_zero K] [char_zero (splitting_field f)] :
264-
(algebra_rat : algebra ℚ (splitting_field f)) = splitting_field.algebra' f :=
265-
rfl -- fails
266-
```
449+
-- The algebra instance deriving from `K` should be definitionally equal to that
450+
-- deriving from the field structure on `splitting_field f`.
451+
example : (add_comm_monoid.nat_module : module ℕ (splitting_field f)) =
452+
@algebra.to_module _ _ _ _ (splitting_field.algebra' f) :=
453+
rfl
267454

268-
Until we resolve these diamonds, it's more convenient to only turn this instance on with
269-
`local attribute [instance]` in places where the benefit of having the instance outweighs the cost.
455+
example : (add_comm_group.int_module _ : module ℤ (splitting_field f)) =
456+
@algebra.to_module _ _ _ _ (splitting_field.algebra' f) :=
457+
rfl
270458

271-
In the meantime, the `splitting_field.algebra` instance below is immune to these particular diamonds
272-
since `K = ℕ` and `K = ℤ` are not possible due to the `field K` assumption. Diamonds in
273-
`algebra ℚ (splitting_field f)` instances are still possible via this instance unfortunately, but
274-
these are less common as they require suitable `char_zero` instances to be present.
275-
-/
276-
instance algebra' {R} [comm_semiring R] [algebra R K] : algebra R (splitting_field f) :=
277-
splitting_field_aux.algebra _ _
459+
example [char_zero K] : (splitting_field.algebra' f) = algebra_rat :=
460+
rfl
278461

279-
instance : algebra K (splitting_field f) :=
280-
splitting_field_aux.algebra _ _
462+
example [char_zero K] : (splitting_field.algebra' f) = algebra_rat :=
463+
rfl
464+
465+
example {q : ℚ[X]} : algebra_int (splitting_field q) = splitting_field.algebra' q := rfl
281466

282467
protected theorem splits : splits (algebra_map K (splitting_field f)) f :=
283468
splitting_field_aux.splits _ _ rfl

src/number_theory/cyclotomic/basic.lean

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -553,12 +553,13 @@ variables [is_domain A] [algebra A K] [is_fraction_ring A K]
553553
section cyclotomic_ring
554554

555555
/-- If `K` is the fraction field of `A`, the `A`-algebra structure on `cyclotomic_field n K`.
556-
This is not an instance since it causes diamonds when `A = ℤ`. -/
556+
-/
557557
@[nolint unused_arguments]
558-
def cyclotomic_field.algebra_base : algebra A (cyclotomic_field n K) :=
559-
((algebra_map K (cyclotomic_field n K)).comp (algebra_map A K)).to_algebra
558+
instance cyclotomic_field.algebra_base : algebra A (cyclotomic_field n K) :=
559+
splitting_field.algebra' (cyclotomic n K)
560560

561-
local attribute [instance] cyclotomic_field.algebra_base
561+
/-- Ensure there are no diamonds when `A = ℤ`. -/
562+
example : algebra_int (cyclotomic_field n ℚ) = cyclotomic_field.algebra_base _ _ _ := rfl
562563

563564
instance cyclotomic_field.no_zero_smul_divisors : no_zero_smul_divisors A (cyclotomic_field n K) :=
564565
no_zero_smul_divisors.of_algebra_map_injective $ function.injective.comp

src/number_theory/cyclotomic/rat.lean

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -129,32 +129,20 @@ begin
129129
exactI is_integral_closure_adjoin_singleton_of_prime_pow hζ,
130130
end
131131

132-
local attribute [-instance] cyclotomic_field.algebra
133-
134132
/-- The integral closure of `ℤ` inside `cyclotomic_field (p ^ k) ℚ` is
135133
`cyclotomic_ring (p ^ k) ℤ ℚ`. -/
136134
lemma cyclotomic_ring_is_integral_closure_of_prime_pow :
137135
is_integral_closure (cyclotomic_ring (p ^ k) ℤ ℚ) ℤ (cyclotomic_field (p ^ k) ℚ) :=
138136
begin
139137
haveI : char_zero ℚ := strict_ordered_semiring.to_char_zero,
140-
haveI : is_cyclotomic_extension {p ^ k} ℚ (cyclotomic_field (p ^ k) ℚ),
141-
{ convert cyclotomic_field.is_cyclotomic_extension (p ^ k) _,
142-
{ exact subsingleton.elim _ _ },
143-
{ exact ne_zero.char_zero } },
144138
have hζ := zeta_spec (p ^ k) ℚ (cyclotomic_field (p ^ k) ℚ),
145139
refine ⟨is_fraction_ring.injective _ _, λ x, ⟨λ h, ⟨⟨x, _⟩, rfl⟩, _⟩⟩,
146140
{ have := (is_integral_closure_adjoin_singleton_of_prime_pow hζ).is_integral_iff,
147141
obtain ⟨y, rfl⟩ := this.1 h,
148-
convert adjoin_mono _ y.2,
149-
{ simp only [eq_iff_true_of_subsingleton] },
150-
{ simp only [eq_iff_true_of_subsingleton] },
151-
{ simp only [pnat.pow_coe, set.singleton_subset_iff, set.mem_set_of_eq],
152-
exact hζ.pow_eq_one } },
153-
{ haveI : is_cyclotomic_extension {p ^ k} ℤ (cyclotomic_ring (p ^ k) ℤ ℚ),
154-
{ convert cyclotomic_ring.is_cyclotomic_extension _ ℤ ℚ,
155-
{ exact subsingleton.elim _ _ },
156-
{ exact ne_zero.char_zero } },
157-
rintro ⟨y, rfl⟩,
142+
refine adjoin_mono _ y.2,
143+
simp only [pnat.pow_coe, set.singleton_subset_iff, set.mem_set_of_eq],
144+
exact hζ.pow_eq_one },
145+
{ rintro ⟨y, rfl⟩,
158146
exact is_integral.algebra_map ((is_cyclotomic_extension.integral {p ^ k} ℤ _) _) }
159147
end
160148

0 commit comments

Comments
 (0)