l3lab/ntp-mathlib huggingface dataset:
/-- If `D` is a unique factorization domain, `f` is a non-zero polynomial in `D[X]`, then `f` has
only finitely many monic factors.
(Note that its factors up to unit may be more than monic factors.)
See also `UniqueFactorizationMonoid.fintypeSubtypeDvd`. -/
noncomputable def fintypeSubtypeMonicDvd (f : D[X]) (hf : f ≠ 0) :
    Fintype { g : D[X] // g.Monic ∧ g ∣ f } := by
  set G := { g : D[X] // g.Monic ∧ g ∣ f }
  let y : Associates D[X] := Associates.mk f
  have hy : y ≠ 0 := Associates.mk_ne_zero.mpr hf
  let H := { x : Associates D[X] // x ∣ y }
  let hfin : Fintype H := UniqueFactorizationMonoid.fintypeSubtypeDvd y hy
  let i : G → H := fun x ↦ ⟨Associates.mk x.1, Associates.mk_dvd_mk.2 x.2.2⟩
  

Proof state:
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommRing S
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
D : Type u
inst✝² : CommRing D
inst✝¹ : IsDomain D
inst✝ : UniqueFactorizationMonoid D
f : D[X]
hf : f ≠ 0
G : Type u := { g // Monic g ∧ g ∣ f }
y : Associates D[X] := Associates.mk f
hy : y ≠ 0
H : Type u := { x // x ∣ y }
hfin : Fintype H := fintypeSubtypeDvd y hy
i : G → H := fun x => { val := Associates.mk ↑x, property := (_ : Associates.mk ↑x ∣ Associates.mk f) }
⊢ Fintype G

Next tactic:
refine Fintype.ofInjective i fun x y heq ↦ ?_
/-- If `D` is a unique factorization domain, `f` is a non-zero polynomial in `D[X]`, then `f` has
only finitely many monic factors.
(Note that its factors up to unit may be more than monic factors.)
See also `UniqueFactorizationMonoid.fintypeSubtypeDvd`. -/
noncomputable def fintypeSubtypeMonicDvd (f : D[X]) (hf : f ≠ 0) :
    Fintype { g : D[X] // g.Monic ∧ g ∣ f } := by
  set G := { g : D[X] // g.Monic ∧ g ∣ f }
  let y : Associates D[X] := Associates.mk f
  have hy : y ≠ 0 := Associates.mk_ne_zero.mpr hf
  let H := { x : Associates D[X] // x ∣ y }
  let hfin : Fintype H := UniqueFactorizationMonoid.fintypeSubtypeDvd y hy
  let i : G → H := fun x ↦ ⟨Associates.mk x.1, Associates.mk_dvd_mk.2 x.2.2⟩
  refine Fintype.ofInjective i fun x y heq ↦ ?_
  

Proof state:
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommRing S
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
D : Type u
inst✝² : CommRing D
inst✝¹ : IsDomain D
inst✝ : UniqueFactorizationMonoid D
f : D[X]
hf : f ≠ 0
G : Type u := { g // Monic g ∧ g ∣ f }
y✝ : Associates D[X] := Associates.mk f
hy : y✝ ≠ 0
H : Type u := { x // x ∣ y✝ }
hfin : Fintype H := fintypeSubtypeDvd y✝ hy
i : G → H := fun x => { val := Associates.mk ↑x, property := (_ : Associates.mk ↑x ∣ Associates.mk f) }
x y : G
heq : i x = i y
⊢ x = y

Next tactic:
rw [Subtype.mk.injEq] at heq ⊢
/-- If `D` is a unique factorization domain, `f` is a non-zero polynomial in `D[X]`, then `f` has
only finitely many monic factors.
(Note that its factors up to unit may be more than monic factors.)
See also `UniqueFactorizationMonoid.fintypeSubtypeDvd`. -/
noncomputable def fintypeSubtypeMonicDvd (f : D[X]) (hf : f ≠ 0) :
    Fintype { g : D[X] // g.Monic ∧ g ∣ f } := by
  set G := { g : D[X] // g.Monic ∧ g ∣ f }
  let y : Associates D[X] := Associates.mk f
  have hy : y ≠ 0 := Associates.mk_ne_zero.mpr hf
  let H := { x : Associates D[X] // x ∣ y }
  let hfin : Fintype H := UniqueFactorizationMonoid.fintypeSubtypeDvd y hy
  let i : G → H := fun x ↦ ⟨Associates.mk x.1, Associates.mk_dvd_mk.2 x.2.2⟩
  refine Fintype.ofInjective i fun x y heq ↦ ?_
  rw [Subtype.mk.injEq] at heq ⊢
  

Proof state:
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommRing S
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
D : Type u
inst✝² : CommRing D
inst✝¹ : IsDomain D
inst✝ : UniqueFactorizationMonoid D
f : D[X]
hf : f ≠ 0
G : Type u := { g // Monic g ∧ g ∣ f }
y✝ : Associates D[X] := Associates.mk f
hy : y✝ ≠ 0
H : Type u := { x // x ∣ y✝ }
hfin : Fintype H := fintypeSubtypeDvd y✝ hy
i : G → H := fun x => { val := Associates.mk ↑x, property := (_ : Associates.mk ↑x ∣ Associates.mk f) }
x y : G
heq : Associates.mk ↑x = Associates.mk ↑y
⊢ ↑x = ↑y

Next tactic:
exact eq_of_monic_of_associated x.2.1 y.2.1 (Associates.mk_eq_mk_iff_associated.mp heq)
attribute [-instance] Polynomial.semiring Polynomial.commSemiring in
private instance : CancelCommMonoidWithZero (MvPolynomial (Fin d) D)[X] := by
  

Proof state:
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommRing S
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
D : Type u
inst✝² : CommRing D
inst✝¹ : IsDomain D
inst✝ : UniqueFactorizationMonoid D
d : ℕ
⊢ CancelCommMonoidWithZero (MvPolynomial (Fin d) D)[X]

Next tactic:
apply IsDomain.toCancelCommMonoidWithZero
private theorem uniqueFactorizationMonoid_of_fintype [Fintype σ] :
    UniqueFactorizationMonoid (MvPolynomial σ D) :=
  (renameEquiv D (Fintype.equivFin σ)).toMulEquiv.symm.uniqueFactorizationMonoid <| by
    

Proof state:
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁷ : CommRing R
inst✝⁶ : CommRing S
inst✝⁵ : AddCommGroup M
inst✝⁴ : Module R M
D : Type u
inst✝³ : CommRing D
inst✝² : IsDomain D
inst✝¹ : UniqueFactorizationMonoid D
d : ℕ
inst✝ : Fintype σ
⊢ UniqueFactorizationMonoid (MvPolynomial (Fin (Fintype.card σ)) D)

Next tactic:
induction' Fintype.card σ with d hd
private theorem uniqueFactorizationMonoid_of_fintype [Fintype σ] :
    UniqueFactorizationMonoid (MvPolynomial σ D) :=
  (renameEquiv D (Fintype.equivFin σ)).toMulEquiv.symm.uniqueFactorizationMonoid <| by
    induction' Fintype.card σ with d hd
    · 

Proof state:
case zero
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁷ : CommRing R
inst✝⁶ : CommRing S
inst✝⁵ : AddCommGroup M
inst✝⁴ : Module R M
D : Type u
inst✝³ : CommRing D
inst✝² : IsDomain D
inst✝¹ : UniqueFactorizationMonoid D
d : ℕ
inst✝ : Fintype σ
⊢ UniqueFactorizationMonoid (MvPolynomial (Fin Nat.zero) D)

Next tactic:
apply (isEmptyAlgEquiv D (Fin 0)).toMulEquiv.symm.uniqueFactorizationMonoid
private theorem uniqueFactorizationMonoid_of_fintype [Fintype σ] :
    UniqueFactorizationMonoid (MvPolynomial σ D) :=
  (renameEquiv D (Fintype.equivFin σ)).toMulEquiv.symm.uniqueFactorizationMonoid <| by
    induction' Fintype.card σ with d hd
    · apply (isEmptyAlgEquiv D (Fin 0)).toMulEquiv.symm.uniqueFactorizationMonoid
      

Proof state:
case zero
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁷ : CommRing R
inst✝⁶ : CommRing S
inst✝⁵ : AddCommGroup M
inst✝⁴ : Module R M
D : Type u
inst✝³ : CommRing D
inst✝² : IsDomain D
inst✝¹ : UniqueFactorizationMonoid D
d : ℕ
inst✝ : Fintype σ
⊢ UniqueFactorizationMonoid D

Next tactic:
infer_instance
private theorem uniqueFactorizationMonoid_of_fintype [Fintype σ] :
    UniqueFactorizationMonoid (MvPolynomial σ D) :=
  (renameEquiv D (Fintype.equivFin σ)).toMulEquiv.symm.uniqueFactorizationMonoid <| by
    induction' Fintype.card σ with d hd
    · apply (isEmptyAlgEquiv D (Fin 0)).toMulEquiv.symm.uniqueFactorizationMonoid
      infer_instance
    · 

Proof state:
case succ
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁷ : CommRing R
inst✝⁶ : CommRing S
inst✝⁵ : AddCommGroup M
inst✝⁴ : Module R M
D : Type u
inst✝³ : CommRing D
inst✝² : IsDomain D
inst✝¹ : UniqueFactorizationMonoid D
d✝ : ℕ
inst✝ : Fintype σ
d : ℕ
hd : UniqueFactorizationMonoid (MvPolynomial (Fin d) D)
⊢ UniqueFactorizationMonoid (MvPolynomial (Fin (Nat.succ d)) D)

Next tactic:
rw [Nat.succ_eq_add_one d]
private theorem uniqueFactorizationMonoid_of_fintype [Fintype σ] :
    UniqueFactorizationMonoid (MvPolynomial σ D) :=
  (renameEquiv D (Fintype.equivFin σ)).toMulEquiv.symm.uniqueFactorizationMonoid <| by
    induction' Fintype.card σ with d hd
    · apply (isEmptyAlgEquiv D (Fin 0)).toMulEquiv.symm.uniqueFactorizationMonoid
      infer_instance
    · rw [Nat.succ_eq_add_one d]
      

Proof state:
case succ
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁷ : CommRing R
inst✝⁶ : CommRing S
inst✝⁵ : AddCommGroup M
inst✝⁴ : Module R M
D : Type u
inst✝³ : CommRing D
inst✝² : IsDomain D
inst✝¹ : UniqueFactorizationMonoid D
d✝ : ℕ
inst✝ : Fintype σ
d : ℕ
hd : UniqueFactorizationMonoid (MvPolynomial (Fin d) D)
⊢ UniqueFactorizationMonoid (MvPolynomial (Fin (d + 1)) D)

Next tactic:
apply @MulEquiv.uniqueFactorizationMonoid _ _ (_) (_)
private theorem uniqueFactorizationMonoid_of_fintype [Fintype σ] :
    UniqueFactorizationMonoid (MvPolynomial σ D) :=
  (renameEquiv D (Fintype.equivFin σ)).toMulEquiv.symm.uniqueFactorizationMonoid <| by
    induction' Fintype.card σ with d hd
    · apply (isEmptyAlgEquiv D (Fin 0)).toMulEquiv.symm.uniqueFactorizationMonoid
      infer_instance
    · rw [Nat.succ_eq_add_one d]
      apply @MulEquiv.uniqueFactorizationMonoid _ _ (_) (_)
      · 

Proof state:
case succ.e
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁷ : CommRing R
inst✝⁶ : CommRing S
inst✝⁵ : AddCommGroup M
inst✝⁴ : Module R M
D : Type u
inst✝³ : CommRing D
inst✝² : IsDomain D
inst✝¹ : UniqueFactorizationMonoid D
d✝ : ℕ
inst✝ : Fintype σ
d : ℕ
hd : UniqueFactorizationMonoid (MvPolynomial (Fin d) D)
⊢ ?m.1076862 ≃* MvPolynomial (Fin (d + 1)) D

Next tactic:
exact (finSuccEquiv D d).toMulEquiv.symm
private theorem uniqueFactorizationMonoid_of_fintype [Fintype σ] :
    UniqueFactorizationMonoid (MvPolynomial σ D) :=
  (renameEquiv D (Fintype.equivFin σ)).toMulEquiv.symm.uniqueFactorizationMonoid <| by
    induction' Fintype.card σ with d hd
    · apply (isEmptyAlgEquiv D (Fin 0)).toMulEquiv.symm.uniqueFactorizationMonoid
      infer_instance
    · rw [Nat.succ_eq_add_one d]
      apply @MulEquiv.uniqueFactorizationMonoid _ _ (_) (_)
      · exact (finSuccEquiv D d).toMulEquiv.symm
      · 

Proof state:
case succ.hα
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁷ : CommRing R
inst✝⁶ : CommRing S
inst✝⁵ : AddCommGroup M
inst✝⁴ : Module R M
D : Type u
inst✝³ : CommRing D
inst✝² : IsDomain D
inst✝¹ : UniqueFactorizationMonoid D
d✝ : ℕ
inst✝ : Fintype σ
d : ℕ
hd : UniqueFactorizationMonoid (MvPolynomial (Fin d) D)
⊢ UniqueFactorizationMonoid (MvPolynomial (Fin d) D)[X]

Next tactic:
apply @Polynomial.uniqueFactorizationMonoid (MvPolynomial (Fin d) D) _ _ ?_
private theorem uniqueFactorizationMonoid_of_fintype [Fintype σ] :
    UniqueFactorizationMonoid (MvPolynomial σ D) :=
  (renameEquiv D (Fintype.equivFin σ)).toMulEquiv.symm.uniqueFactorizationMonoid <| by
    induction' Fintype.card σ with d hd
    · apply (isEmptyAlgEquiv D (Fin 0)).toMulEquiv.symm.uniqueFactorizationMonoid
      infer_instance
    · rw [Nat.succ_eq_add_one d]
      apply @MulEquiv.uniqueFactorizationMonoid _ _ (_) (_)
      · exact (finSuccEquiv D d).toMulEquiv.symm
      · apply @Polynomial.uniqueFactorizationMonoid (MvPolynomial (Fin d) D) _ _ ?_
        

Proof state:
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁷ : CommRing R
inst✝⁶ : CommRing S
inst✝⁵ : AddCommGroup M
inst✝⁴ : Module R M
D : Type u
inst✝³ : CommRing D
inst✝² : IsDomain D
inst✝¹ : UniqueFactorizationMonoid D
d✝ : ℕ
inst✝ : Fintype σ
d : ℕ
hd : UniqueFactorizationMonoid (MvPolynomial (Fin d) D)
⊢ UniqueFactorizationMonoid (MvPolynomial (Fin d) D)

Next tactic:
assumption
instance (priority := 100) uniqueFactorizationMonoid :
    UniqueFactorizationMonoid (MvPolynomial σ D) := by
  

Proof state:
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommRing S
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
D : Type u
inst✝² : CommRing D
inst✝¹ : IsDomain D
inst✝ : UniqueFactorizationMonoid D
d : ℕ
⊢ UniqueFactorizationMonoid (MvPolynomial σ D)

Next tactic:
rw [iff_exists_prime_factors]
instance (priority := 100) uniqueFactorizationMonoid :
    UniqueFactorizationMonoid (MvPolynomial σ D) := by
  rw [iff_exists_prime_factors]
  

Proof state:
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommRing S
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
D : Type u
inst✝² : CommRing D
inst✝¹ : IsDomain D
inst✝ : UniqueFactorizationMonoid D
d : ℕ
⊢ ∀ (a : MvPolynomial σ D), a ≠ 0 → ∃ f, (∀ b ∈ f, Prime b) ∧ Associated (Multiset.prod f) a

Next tactic:
intro a ha
instance (priority := 100) uniqueFactorizationMonoid :
    UniqueFactorizationMonoid (MvPolynomial σ D) := by
  rw [iff_exists_prime_factors]
  intro a ha; 

Proof state:
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommRing S
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
D : Type u
inst✝² : CommRing D
inst✝¹ : IsDomain D
inst✝ : UniqueFactorizationMonoid D
d : ℕ
a : MvPolynomial σ D
ha : a ≠ 0
⊢ ∃ f, (∀ b ∈ f, Prime b) ∧ Associated (Multiset.prod f) a

Next tactic:
obtain ⟨s, a', rfl⟩ := exists_finset_rename a
instance (priority := 100) uniqueFactorizationMonoid :
    UniqueFactorizationMonoid (MvPolynomial σ D) := by
  rw [iff_exists_prime_factors]
  intro a ha; obtain ⟨s, a', rfl⟩ := exists_finset_rename a
  

Proof state:
case intro.intro
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommRing S
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
D : Type u
inst✝² : CommRing D
inst✝¹ : IsDomain D
inst✝ : UniqueFactorizationMonoid D
d : ℕ
s : Finset σ
a' : MvPolynomial { x // x ∈ s } D
ha : (rename Subtype.val) a' ≠ 0
⊢ ∃ f, (∀ b ∈ f, Prime b) ∧ Associated (Multiset.prod f) ((rename Subtype.val) a')

Next tactic:
obtain ⟨w, h, u, hw⟩ :=
    iff_exists_prime_factors.1 (uniqueFactorizationMonoid_of_fintype s) a' fun h =>
      ha <| by simp [h]
instance (priority := 100) uniqueFactorizationMonoid :
    UniqueFactorizationMonoid (MvPolynomial σ D) := by
  rw [iff_exists_prime_factors]
  intro a ha; obtain ⟨s, a', rfl⟩ := exists_finset_rename a
  obtain ⟨w, h, u, hw⟩ :=
    iff_exists_prime_factors.1 (uniqueFactorizationMonoid_of_fintype s) a' fun h =>
      ha <| by 

Proof state:
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommRing S
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
D : Type u
inst✝² : CommRing D
inst✝¹ : IsDomain D
inst✝ : UniqueFactorizationMonoid D
d : ℕ
s : Finset σ
a' : MvPolynomial { x // x ∈ s } D
ha : (rename Subtype.val) a' ≠ 0
h : a' = 0
⊢ (rename Subtype.val) a' = 0

Next tactic:
simp [h]
instance (priority := 100) uniqueFactorizationMonoid :
    UniqueFactorizationMonoid (MvPolynomial σ D) := by
  rw [iff_exists_prime_factors]
  intro a ha; obtain ⟨s, a', rfl⟩ := exists_finset_rename a
  obtain ⟨w, h, u, hw⟩ :=
    iff_exists_prime_factors.1 (uniqueFactorizationMonoid_of_fintype s) a' fun h =>
      ha <| by simp [h]
  

Proof state:
case intro.intro.intro.intro.intro
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommRing S
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
D : Type u
inst✝² : CommRing D
inst✝¹ : IsDomain D
inst✝ : UniqueFactorizationMonoid D
d : ℕ
s : Finset σ
a' : MvPolynomial { x // x ∈ s } D
ha : (rename Subtype.val) a' ≠ 0
w : Multiset (MvPolynomial { x // x ∈ s } D)
h : ∀ b ∈ w, Prime b
u : (MvPolynomial { x // x ∈ s } D)ˣ
hw : Multiset.prod w * ↑u = a'
⊢ ∃ f, (∀ b ∈ f, Prime b) ∧ Associated (Multiset.prod f) ((rename Subtype.val) a')

Next tactic:
exact
    ⟨w.map (rename (↑)), fun b hb =>
      let ⟨b', hb', he⟩ := Multiset.mem_map.1 hb
      he ▸ (prime_rename_iff ↑s).2 (h b' hb'),
      Units.map (@rename s σ D _ (↑)).toRingHom.toMonoidHom u, by
      erw [Multiset.prod_hom, ← map_mul, hw]⟩
instance (priority := 100) uniqueFactorizationMonoid :
    UniqueFactorizationMonoid (MvPolynomial σ D) := by
  rw [iff_exists_prime_factors]
  intro a ha; obtain ⟨s, a', rfl⟩ := exists_finset_rename a
  obtain ⟨w, h, u, hw⟩ :=
    iff_exists_prime_factors.1 (uniqueFactorizationMonoid_of_fintype s) a' fun h =>
      ha <| by simp [h]
  exact
    ⟨w.map (rename (↑)), fun b hb =>
      let ⟨b', hb', he⟩ := Multiset.mem_map.1 hb
      he ▸ (prime_rename_iff ↑s).2 (h b' hb'),
      Units.map (@rename s σ D _ (↑)).toRingHom.toMonoidHom u, by
      

Proof state:
R : Type u
S : Type u_1
σ : Type v
M : Type w
inst✝⁶ : CommRing R
inst✝⁵ : CommRing S
inst✝⁴ : AddCommGroup M
inst✝³ : Module R M
D : Type u
inst✝² : CommRing D
inst✝¹ : IsDomain D
inst✝ : UniqueFactorizationMonoid D
d : ℕ
s : Finset σ
a' : MvPolynomial { x // x ∈ s } D
ha : (rename Subtype.val) a' ≠ 0
w : Multiset (MvPolynomial { x // x ∈ s } D)
h : ∀ b ∈ w, Prime b
u : (MvPolynomial { x // x ∈ s } D)ˣ
hw : Multiset.prod w * ↑u = a'
⊢ Multiset.prod (Multiset.map (⇑(rename Subtype.val)) w) * ↑((Units.map ↑↑(rename Subtype.val)) u) =
    (rename Subtype.val) a'

Next tactic:
erw [Multiset.prod_hom, ← map_mul, hw]
/-- `rootsOfUnity k M` is the subgroup of elements `m : Mˣ` that satisfy `m ^ k = 1`. -/
def rootsOfUnity (k : ℕ+) (M : Type*) [CommMonoid M] : Subgroup Mˣ where
  carrier := {ζ | ζ ^ (k : ℕ) = 1}
  one_mem' := one_pow _
  mul_mem' _ _ := by 

Proof state:
M✝ : Type u_1
N : Type u_2
G : Type u_3
R : Type u_4
S : Type u_5
F : Type u_6
inst✝³ : CommMonoid M✝
inst✝² : CommMonoid N
inst✝¹ : DivisionCommMonoid G
k✝ l k : ℕ+
M : Type u_7
inst✝ : CommMonoid M
a✝ b✝ : Mˣ
x✝¹ : a✝ ∈ {ζ | ζ ^ ↑k = 1}
x✝ : b✝ ∈ {ζ | ζ ^ ↑k = 1}
⊢ a✝ * b✝ ∈ {ζ | ζ ^ ↑k = 1}

Next tactic:
simp_all only [Set.mem_setOf_eq, mul_pow, one_mul]
/-- `rootsOfUnity k M` is the subgroup of elements `m : Mˣ` that satisfy `m ^ k = 1`. -/
def rootsOfUnity (k : ℕ+) (M : Type*) [CommMonoid M] : Subgroup Mˣ where
  carrier := {ζ | ζ ^ (k : ℕ) = 1}
  one_mem' := one_pow _
  mul_mem' _ _ := by simp_all only [Set.mem_setOf_eq, mul_pow, one_mul]
  inv_mem' _ := by 

Proof state:
M✝ : Type u_1
N : Type u_2
G : Type u_3
R : Type u_4
S : Type u_5
F : Type u_6
inst✝³ : CommMonoid M✝
inst✝² : CommMonoid N
inst✝¹ : DivisionCommMonoid G
k✝ l k : ℕ+
M : Type u_7
inst✝ : CommMonoid M
x✝¹ : Mˣ
x✝ :
  x✝¹ ∈
    {
          toSubsemigroup :=
            { carrier := {ζ | ζ ^ ↑k = 1},
              mul_mem' := (_ : ∀ {a b : Mˣ}, a ∈ {ζ | ζ ^ ↑k = 1} → b ∈ {ζ | ζ ^ ↑k = 1} → (a * b) ^ ↑k = 1) },
          one_mem' := (_ : 1 ^ ↑k = 1) }.toSubsemigroup.carrier
⊢ x✝¹⁻¹ ∈
    {
          toSubsemigroup :=
            { carrier := {ζ | ζ ^ ↑k = 1},
              mul_mem' := (_ : ∀ {a b : Mˣ}, a ∈ {ζ | ζ ^ ↑k = 1} → b ∈ {ζ | ζ ^ ↑k = 1} → (a * b) ^ ↑k = 1) },
          one_mem' := (_ : 1 ^ ↑k = 1) }.toSubsemigroup.carrier

Next tactic:
simp_all only [Set.mem_setOf_eq, inv_pow, inv_one]
theorem mem_rootsOfUnity' (k : ℕ+) (ζ : Mˣ) : ζ ∈ rootsOfUnity k M ↔ (ζ : M) ^ (k : ℕ) = 1 := by
  

Proof state:
M : Type u_1
N : Type u_2
G : Type u_3
R : Type u_4
S : Type u_5
F : Type u_6
inst✝² : CommMonoid M
inst✝¹ : CommMonoid N
inst✝ : DivisionCommMonoid G
k✝ l k : ℕ+
ζ : Mˣ
⊢ ζ ∈ rootsOfUnity k M ↔ ↑ζ ^ ↑k = 1

Next tactic:
rw [mem_rootsOfUnity]
theorem mem_rootsOfUnity' (k : ℕ+) (ζ : Mˣ) : ζ ∈ rootsOfUnity k M ↔ (ζ : M) ^ (k : ℕ) = 1 := by
  rw [mem_rootsOfUnity]; 

Proof state:
M : Type u_1
N : Type u_2
G : Type u_3
R : Type u_4
S : Type u_5
F : Type u_6
inst✝² : CommMonoid M
inst✝¹ : CommMonoid N
inst✝ : DivisionCommMonoid G
k✝ l k : ℕ+
ζ : Mˣ
⊢ ζ ^ ↑k = 1 ↔ ↑ζ ^ ↑k = 1

Next tactic:
norm_cast
theorem rootsOfUnity_le_of_dvd (h : k ∣ l) : rootsOfUnity k M ≤ rootsOfUnity l M := by
  

Proof state:
M : Type u_1
N : Type u_2
G : Type u_3
R : Type u_4
S : Type u_5
F : Type u_6
inst✝² : CommMonoid M
inst✝¹ : CommMonoid N
inst✝ : DivisionCommMonoid G
k l : ℕ+
h : k ∣ l
⊢ rootsOfUnity k M ≤ rootsOfUnity l M

Next tactic:
obtain ⟨d, rfl⟩ := h
theorem rootsOfUnity_le_of_dvd (h : k ∣ l) : rootsOfUnity k M ≤ rootsOfUnity l M := by
  obtain ⟨d, rfl⟩ := h
  

Proof state:
case intro
M : Type u_1
N : Type u_2
G : Type u_3
R : Type u_4
S : Type u_5
F : Type u_6
inst✝² : CommMonoid M
inst✝¹ : CommMonoid N
inst✝ : DivisionCommMonoid G
k d : ℕ+
⊢ rootsOfUnity k M ≤ rootsOfUnity (k * d) M

Next tactic:
intro ζ h
theorem rootsOfUnity_le_of_dvd (h : k ∣ l) : rootsOfUnity k M ≤ rootsOfUnity l M := by
  obtain ⟨d, rfl⟩ := h
  intro ζ h
  

Proof state:
case intro
M : Type u_1
N : Type u_2
G : Type u_3
R : Type u_4
S : Type u_5
F : Type u_6
inst✝² : CommMonoid M
inst✝¹ : CommMonoid N
inst✝ : DivisionCommMonoid G
k d : ℕ+
ζ : Mˣ
h : ζ ∈ rootsOfUnity k M
⊢ ζ ∈ rootsOfUnity (k * d) M

Next tactic:
simp_all only [mem_rootsOfUnity, PNat.mul_coe, pow_mul, one_pow]
theorem map_rootsOfUnity (f : Mˣ →* Nˣ) (k : ℕ+) : (rootsOfUnity k M).map f ≤ rootsOfUnity k N := by
  

Proof state:
M : Type u_1
N : Type u_2
G : Type u_3
R : Type u_4
S : Type u_5
F : Type u_6
inst✝² : CommMonoid M
inst✝¹ : CommMonoid N
inst✝ : DivisionCommMonoid G
k✝ l : ℕ+
f : Mˣ →* Nˣ
k : ℕ+
⊢ Subgroup.map f (rootsOfUnity k M) ≤ rootsOfUnity k N

Next tactic:
rintro _ ⟨ζ, h, rfl⟩
theorem map_rootsOfUnity (f : Mˣ →* Nˣ) (k : ℕ+) : (rootsOfUnity k M).map f ≤ rootsOfUnity k N := by
  rintro _ ⟨ζ, h, rfl⟩
  

Proof state:
case intro.intro
M : Type u_1
N : Type u_2
G : Type u_3
R : Type u_4
S : Type u_5
F : Type u_6
inst✝² : CommMonoid M
inst✝¹ : CommMonoid N
inst✝ : DivisionCommMonoid G
k✝ l : ℕ+
f : Mˣ →* Nˣ
k : ℕ+
ζ : Mˣ
h : ζ ∈ ↑(rootsOfUnity k M)
⊢ f ζ ∈ rootsOfUnity k N

Next tactic:
simp_all only [← map_pow, mem_rootsOfUnity, SetLike.mem_coe, MonoidHom.map_one]
@[norm_cast]
theorem rootsOfUnity.coe_pow [CommMonoid R] (ζ : rootsOfUnity k R) (m : ℕ) :
    (((ζ ^ m :) : Rˣ) : R) = ((ζ : Rˣ) : R) ^ m := by
  

Proof state:
M : Type u_1
N : Type u_2
G : Type u_3
R : Type u_4
S : Type u_5
F : Type u_6
inst✝³ : CommMonoid M
inst✝² : CommMonoid N
inst✝¹ : DivisionCommMonoid G
k l : ℕ+
inst✝ : CommMonoid R
ζ : ↥(rootsOfUnity k R)
m : ℕ
⊢ ↑↑(ζ ^ m) = ↑↑ζ ^ m

Next tactic:
rw [Subgroup.coe_pow, Units.val_pow_eq_pow_val]
/-- Restrict a ring homomorphism to the nth roots of unity. -/
def restrictRootsOfUnity [RingHomClass F R S] (σ : F) (n : ℕ+) :
    rootsOfUnity n R →* rootsOfUnity n S :=
  let h : ∀ ξ : rootsOfUnity n R, (σ (ξ : Rˣ)) ^ (n : ℕ) = 1 := fun ξ => by
    

Proof state:
M : Type u_1
N : Type u_2
G : Type u_3
R : Type u_4
S : Type u_5
F : Type u_6
inst✝⁵ : CommMonoid M
inst✝⁴ : CommMonoid N
inst✝³ : DivisionCommMonoid G
k l : ℕ+
inst✝² : CommSemiring R
inst✝¹ : CommSemiring S
inst✝ : RingHomClass F R S
σ : F
n : ℕ+
ξ : ↥(rootsOfUnity n R)
⊢ σ ↑↑ξ ^ ↑n = 1

Next tactic:
rw [← map_pow, ← Units.val_pow_eq_pow_val, show (ξ : Rˣ) ^ (n : ℕ) = 1 from ξ.2, Units.val_one,
      map_one σ]
/-- Restrict a ring homomorphism to the nth roots of unity. -/
def restrictRootsOfUnity [RingHomClass F R S] (σ : F) (n : ℕ+) :
    rootsOfUnity n R →* rootsOfUnity n S :=
  let h : ∀ ξ : rootsOfUnity n R, (σ (ξ : Rˣ)) ^ (n : ℕ) = 1 := fun ξ => by
    rw [← map_pow, ← Units.val_pow_eq_pow_val, show (ξ : Rˣ) ^ (n : ℕ) = 1 from ξ.2, Units.val_one,
      map_one σ]
  { toFun := fun ξ =>
      ⟨@unitOfInvertible _ _ _ (invertibleOfPowEqOne _ _ (h ξ) n.ne_zero), by
        

Proof state:
M : Type u_1
N : Type u_2
G : Type u_3
R : Type u_4
S : Type u_5
F : Type u_6
inst✝⁵ : CommMonoid M
inst✝⁴ : CommMonoid N
inst✝³ : DivisionCommMonoid G
k l : ℕ+
inst✝² : CommSemiring R
inst✝¹ : CommSemiring S
inst✝ : RingHomClass F R S
σ : F
n : ℕ+
h : ∀ (ξ : ↥(rootsOfUnity n R)), σ ↑↑ξ ^ ↑n = 1 :=
  fun ξ =>
    Eq.mpr (id ((map_pow σ ↑↑ξ ↑n).symm ▸ Eq.refl (σ ↑↑ξ ^ ↑n = 1)))
      (Eq.mpr (id ((Units.val_pow_eq_pow_val ↑ξ ↑n).symm ▸ Eq.refl (σ (↑↑ξ ^ ↑n) = 1)))
        (Eq.mpr
          (id
            ((let_fun this := ξ.property;
              this) ▸
              Eq.refl (σ ↑(↑ξ ^ ↑n) = 1)))
          (Eq.mpr (id (Units.val_one ▸ Eq.refl (σ ↑1 = 1))) (Eq.mpr (id (map_one σ ▸ Eq.refl (σ 1 = 1))) (Eq.refl 1)))))
ξ : ↥(rootsOfUnity n R)
⊢ unitOfInvertible (σ ↑↑ξ) ∈ rootsOfUnity n S

Next tactic:
ext