l3lab/ntp-mathlib huggingface dataset:
/-- Equivalence between the `k`-th roots of unity in `R` and the `k`-th roots of `1`.

This is implemented as equivalence of subtypes,
because `rootsOfUnity` is a subgroup of the group of units,
whereas `nthRoots` is a multiset. -/
def rootsOfUnityEquivNthRoots : rootsOfUnity k R ≃ { x // x ∈ nthRoots k (1 : R) } := by
  refine'
    { toFun := fun x => ⟨(x : Rˣ), mem_rootsOfUnity_iff_mem_nthRoots.mp x.2⟩
      invFun := fun x => ⟨⟨x, ↑x ^ (k - 1 : ℕ), _, _⟩, _⟩
      left_inv := _
      right_inv := _ }
  pick_goal 4; · rintro ⟨x, hx⟩; ext; 

Proof state:
case refine'_4.mk.a.a
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✝¹ : CommRing R
inst✝ : IsDomain R
x : Rˣ
hx : x ∈ rootsOfUnity k R
⊢ ↑↑((fun x =>
            {
              val :=
                { val := ↑x, inv := ↑x ^ (↑k - 1), val_inv := (_ : ↑x * ?m.661189 x ^ (↑k - 1) = 1),
                  inv_val := (_ : ?m.661191 x ^ (↑k - 1) * ↑x = 1) },
              property :=
                (_ :
                  { val := ↑x, inv := ?m.661193 x ^ (↑k - 1), val_inv := (_ : ↑x * ?m.661194 x ^ (↑k - 1) = 1),
                      inv_val := (_ : ?m.661196 x ^ (↑k - 1) * ↑x = 1) } ∈
                    rootsOfUnity k R) })
          ((fun x => { val := ↑↑x, property := (_ : ↑↑x ∈ nthRoots (↑k) 1) }) { val := x, property := hx })) =
    ↑↑{ val := x, property := hx }

Next tactic:
rfl
/-- Equivalence between the `k`-th roots of unity in `R` and the `k`-th roots of `1`.

This is implemented as equivalence of subtypes,
because `rootsOfUnity` is a subgroup of the group of units,
whereas `nthRoots` is a multiset. -/
def rootsOfUnityEquivNthRoots : rootsOfUnity k R ≃ { x // x ∈ nthRoots k (1 : R) } := by
  refine'
    { toFun := fun x => ⟨(x : Rˣ), mem_rootsOfUnity_iff_mem_nthRoots.mp x.2⟩
      invFun := fun x => ⟨⟨x, ↑x ^ (k - 1 : ℕ), _, _⟩, _⟩
      left_inv := _
      right_inv := _ }
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  

Proof state:
case refine'_1
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✝¹ : CommRing R
inst✝ : IsDomain R
x : { x // x ∈ nthRoots (↑k) 1 }
⊢ ↑x * ↑x ^ (↑k - 1) = 1
case refine'_2
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✝¹ : CommRing R
inst✝ : IsDomain R
x : { x // x ∈ nthRoots (↑k) 1 }
⊢ ↑x ^ (↑k - 1) * ↑x = 1
case refine'_3
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✝¹ : CommRing R
inst✝ : IsDomain R
x : { x // x ∈ nthRoots (↑k) 1 }
⊢ { val := ↑x, inv := ↑x ^ (↑k - 1), val_inv := ?refine'_1, inv_val := ?refine'_2 } ∈ rootsOfUnity k R
case refine'_5
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✝¹ : CommRing R
inst✝ : IsDomain R
⊢ Function.RightInverse
    (fun x =>
      {
        val :=
          { val := ↑x, inv := ↑x ^ (↑k - 1), val_inv := (_ : ↑x * ?m.661189 x ^ (↑k - 1) = 1),
            inv_val := (_ : ?m.661191 x ^ (↑k - 1) * ↑x = 1) },
        property :=
          (_ :
            { val := ↑x, inv := ?m.661193 x ^ (↑k - 1), val_inv := (_ : ↑x * ?m.661194 x ^ (↑k - 1) = 1),
                inv_val := (_ : ?m.661196 x ^ (↑k - 1) * ↑x = 1) } ∈
              rootsOfUnity k R) })
    fun x => { val := ↑↑x, property := (_ : ↑↑x ∈ nthRoots (↑k) 1) }

Next tactic:
pick_goal 4
/-- Equivalence between the `k`-th roots of unity in `R` and the `k`-th roots of `1`.

This is implemented as equivalence of subtypes,
because `rootsOfUnity` is a subgroup of the group of units,
whereas `nthRoots` is a multiset. -/
def rootsOfUnityEquivNthRoots : rootsOfUnity k R ≃ { x // x ∈ nthRoots k (1 : R) } := by
  refine'
    { toFun := fun x => ⟨(x : Rˣ), mem_rootsOfUnity_iff_mem_nthRoots.mp x.2⟩
      invFun := fun x => ⟨⟨x, ↑x ^ (k - 1 : ℕ), _, _⟩, _⟩
      left_inv := _
      right_inv := _ }
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  pick_goal 4; · 

Proof state:
case refine'_5
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✝¹ : CommRing R
inst✝ : IsDomain R
⊢ Function.RightInverse
    (fun x =>
      {
        val :=
          { val := ↑x, inv := ↑x ^ (↑k - 1), val_inv := (_ : ↑x * ?m.661189 x ^ (↑k - 1) = 1),
            inv_val := (_ : ?m.661191 x ^ (↑k - 1) * ↑x = 1) },
        property :=
          (_ :
            { val := ↑x, inv := ?m.661193 x ^ (↑k - 1), val_inv := (_ : ↑x * ?m.661194 x ^ (↑k - 1) = 1),
                inv_val := (_ : ?m.661196 x ^ (↑k - 1) * ↑x = 1) } ∈
              rootsOfUnity k R) })
    fun x => { val := ↑↑x, property := (_ : ↑↑x ∈ nthRoots (↑k) 1) }

Next tactic:
rintro ⟨x, hx⟩
/-- Equivalence between the `k`-th roots of unity in `R` and the `k`-th roots of `1`.

This is implemented as equivalence of subtypes,
because `rootsOfUnity` is a subgroup of the group of units,
whereas `nthRoots` is a multiset. -/
def rootsOfUnityEquivNthRoots : rootsOfUnity k R ≃ { x // x ∈ nthRoots k (1 : R) } := by
  refine'
    { toFun := fun x => ⟨(x : Rˣ), mem_rootsOfUnity_iff_mem_nthRoots.mp x.2⟩
      invFun := fun x => ⟨⟨x, ↑x ^ (k - 1 : ℕ), _, _⟩, _⟩
      left_inv := _
      right_inv := _ }
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  pick_goal 4; · rintro ⟨x, hx⟩; 

Proof state:
case refine'_5.mk
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✝¹ : CommRing R
inst✝ : IsDomain R
x : R
hx : x ∈ nthRoots (↑k) 1
⊢ (fun x => { val := ↑↑x, property := (_ : ↑↑x ∈ nthRoots (↑k) 1) })
      ((fun x =>
          {
            val :=
              { val := ↑x, inv := ↑x ^ (↑k - 1), val_inv := (_ : ↑x * ?m.661189 x ^ (↑k - 1) = 1),
                inv_val := (_ : ?m.661191 x ^ (↑k - 1) * ↑x = 1) },
            property :=
              (_ :
                { val := ↑x, inv := ?m.661193 x ^ (↑k - 1), val_inv := (_ : ↑x * ?m.661194 x ^ (↑k - 1) = 1),
                    inv_val := (_ : ?m.661196 x ^ (↑k - 1) * ↑x = 1) } ∈
                  rootsOfUnity k R) })
        { val := x, property := hx }) =
    { val := x, property := hx }

Next tactic:
ext
/-- Equivalence between the `k`-th roots of unity in `R` and the `k`-th roots of `1`.

This is implemented as equivalence of subtypes,
because `rootsOfUnity` is a subgroup of the group of units,
whereas `nthRoots` is a multiset. -/
def rootsOfUnityEquivNthRoots : rootsOfUnity k R ≃ { x // x ∈ nthRoots k (1 : R) } := by
  refine'
    { toFun := fun x => ⟨(x : Rˣ), mem_rootsOfUnity_iff_mem_nthRoots.mp x.2⟩
      invFun := fun x => ⟨⟨x, ↑x ^ (k - 1 : ℕ), _, _⟩, _⟩
      left_inv := _
      right_inv := _ }
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  pick_goal 4; · rintro ⟨x, hx⟩; ext; 

Proof state:
case refine'_5.mk.a
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✝¹ : CommRing R
inst✝ : IsDomain R
x : R
hx : x ∈ nthRoots (↑k) 1
⊢ ↑((fun x => { val := ↑↑x, property := (_ : ↑↑x ∈ nthRoots (↑k) 1) })
        ((fun x =>
            {
              val :=
                { val := ↑x, inv := ↑x ^ (↑k - 1), val_inv := (_ : ↑x * ?m.661189 x ^ (↑k - 1) = 1),
                  inv_val := (_ : ?m.661191 x ^ (↑k - 1) * ↑x = 1) },
              property :=
                (_ :
                  { val := ↑x, inv := ?m.661193 x ^ (↑k - 1), val_inv := (_ : ↑x * ?m.661194 x ^ (↑k - 1) = 1),
                      inv_val := (_ : ?m.661196 x ^ (↑k - 1) * ↑x = 1) } ∈
                    rootsOfUnity k R) })
          { val := x, property := hx })) =
    ↑{ val := x, property := hx }

Next tactic:
rfl
/-- Equivalence between the `k`-th roots of unity in `R` and the `k`-th roots of `1`.

This is implemented as equivalence of subtypes,
because `rootsOfUnity` is a subgroup of the group of units,
whereas `nthRoots` is a multiset. -/
def rootsOfUnityEquivNthRoots : rootsOfUnity k R ≃ { x // x ∈ nthRoots k (1 : R) } := by
  refine'
    { toFun := fun x => ⟨(x : Rˣ), mem_rootsOfUnity_iff_mem_nthRoots.mp x.2⟩
      invFun := fun x => ⟨⟨x, ↑x ^ (k - 1 : ℕ), _, _⟩, _⟩
      left_inv := _
      right_inv := _ }
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  

Proof state:
case refine'_1
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✝¹ : CommRing R
inst✝ : IsDomain R
x : { x // x ∈ nthRoots (↑k) 1 }
⊢ ↑x * ↑x ^ (↑k - 1) = 1
case refine'_2
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✝¹ : CommRing R
inst✝ : IsDomain R
x : { x // x ∈ nthRoots (↑k) 1 }
⊢ ↑x ^ (↑k - 1) * ↑x = 1
case refine'_3
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✝¹ : CommRing R
inst✝ : IsDomain R
x : { x // x ∈ nthRoots (↑k) 1 }
⊢ { val := ↑x, inv := ↑x ^ (↑k - 1), val_inv := ?refine'_1, inv_val := ?refine'_2 } ∈ rootsOfUnity k R

Next tactic:
all_goals
    rcases x with ⟨x, hx⟩; rw [mem_nthRoots k.pos] at hx
    simp only [Subtype.coe_mk, ← pow_succ, ← pow_succ', hx,
      tsub_add_cancel_of_le (show 1 ≤ (k : ℕ) from k.one_le)]
/-- Equivalence between the `k`-th roots of unity in `R` and the `k`-th roots of `1`.

This is implemented as equivalence of subtypes,
because `rootsOfUnity` is a subgroup of the group of units,
whereas `nthRoots` is a multiset. -/
def rootsOfUnityEquivNthRoots : rootsOfUnity k R ≃ { x // x ∈ nthRoots k (1 : R) } := by
  refine'
    { toFun := fun x => ⟨(x : Rˣ), mem_rootsOfUnity_iff_mem_nthRoots.mp x.2⟩
      invFun := fun x => ⟨⟨x, ↑x ^ (k - 1 : ℕ), _, _⟩, _⟩
      left_inv := _
      right_inv := _ }
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  all_goals
    

Proof state:
case refine'_1
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✝¹ : CommRing R
inst✝ : IsDomain R
x : { x // x ∈ nthRoots (↑k) 1 }
⊢ ↑x * ↑x ^ (↑k - 1) = 1

Next tactic:
rcases x with ⟨x, hx⟩
/-- Equivalence between the `k`-th roots of unity in `R` and the `k`-th roots of `1`.

This is implemented as equivalence of subtypes,
because `rootsOfUnity` is a subgroup of the group of units,
whereas `nthRoots` is a multiset. -/
def rootsOfUnityEquivNthRoots : rootsOfUnity k R ≃ { x // x ∈ nthRoots k (1 : R) } := by
  refine'
    { toFun := fun x => ⟨(x : Rˣ), mem_rootsOfUnity_iff_mem_nthRoots.mp x.2⟩
      invFun := fun x => ⟨⟨x, ↑x ^ (k - 1 : ℕ), _, _⟩, _⟩
      left_inv := _
      right_inv := _ }
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  all_goals
    rcases x with ⟨x, hx⟩; 

Proof state:
case refine'_1.mk
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✝¹ : CommRing R
inst✝ : IsDomain R
x : R
hx : x ∈ nthRoots (↑k) 1
⊢ ↑{ val := x, property := hx } * ↑{ val := x, property := hx } ^ (↑k - 1) = 1

Next tactic:
rw [mem_nthRoots k.pos] at hx
/-- Equivalence between the `k`-th roots of unity in `R` and the `k`-th roots of `1`.

This is implemented as equivalence of subtypes,
because `rootsOfUnity` is a subgroup of the group of units,
whereas `nthRoots` is a multiset. -/
def rootsOfUnityEquivNthRoots : rootsOfUnity k R ≃ { x // x ∈ nthRoots k (1 : R) } := by
  refine'
    { toFun := fun x => ⟨(x : Rˣ), mem_rootsOfUnity_iff_mem_nthRoots.mp x.2⟩
      invFun := fun x => ⟨⟨x, ↑x ^ (k - 1 : ℕ), _, _⟩, _⟩
      left_inv := _
      right_inv := _ }
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  all_goals
    rcases x with ⟨x, hx⟩; rw [mem_nthRoots k.pos] at hx
    

Proof state:
case refine'_1.mk
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✝¹ : CommRing R
inst✝ : IsDomain R
x : R
hx✝ : x ∈ nthRoots (↑k) 1
hx : x ^ ↑k = 1
⊢ ↑{ val := x, property := hx✝ } * ↑{ val := x, property := hx✝ } ^ (↑k - 1) = 1

Next tactic:
simp only [Subtype.coe_mk, ← pow_succ, ← pow_succ', hx,
      tsub_add_cancel_of_le (show 1 ≤ (k : ℕ) from k.one_le)]
/-- Equivalence between the `k`-th roots of unity in `R` and the `k`-th roots of `1`.

This is implemented as equivalence of subtypes,
because `rootsOfUnity` is a subgroup of the group of units,
whereas `nthRoots` is a multiset. -/
def rootsOfUnityEquivNthRoots : rootsOfUnity k R ≃ { x // x ∈ nthRoots k (1 : R) } := by
  refine'
    { toFun := fun x => ⟨(x : Rˣ), mem_rootsOfUnity_iff_mem_nthRoots.mp x.2⟩
      invFun := fun x => ⟨⟨x, ↑x ^ (k - 1 : ℕ), _, _⟩, _⟩
      left_inv := _
      right_inv := _ }
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  all_goals
    

Proof state:
case refine'_2
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✝¹ : CommRing R
inst✝ : IsDomain R
x : { x // x ∈ nthRoots (↑k) 1 }
⊢ ↑x ^ (↑k - 1) * ↑x = 1

Next tactic:
rcases x with ⟨x, hx⟩
/-- Equivalence between the `k`-th roots of unity in `R` and the `k`-th roots of `1`.

This is implemented as equivalence of subtypes,
because `rootsOfUnity` is a subgroup of the group of units,
whereas `nthRoots` is a multiset. -/
def rootsOfUnityEquivNthRoots : rootsOfUnity k R ≃ { x // x ∈ nthRoots k (1 : R) } := by
  refine'
    { toFun := fun x => ⟨(x : Rˣ), mem_rootsOfUnity_iff_mem_nthRoots.mp x.2⟩
      invFun := fun x => ⟨⟨x, ↑x ^ (k - 1 : ℕ), _, _⟩, _⟩
      left_inv := _
      right_inv := _ }
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  all_goals
    rcases x with ⟨x, hx⟩; 

Proof state:
case refine'_2.mk
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✝¹ : CommRing R
inst✝ : IsDomain R
x : R
hx : x ∈ nthRoots (↑k) 1
⊢ ↑{ val := x, property := hx } ^ (↑k - 1) * ↑{ val := x, property := hx } = 1

Next tactic:
rw [mem_nthRoots k.pos] at hx
/-- Equivalence between the `k`-th roots of unity in `R` and the `k`-th roots of `1`.

This is implemented as equivalence of subtypes,
because `rootsOfUnity` is a subgroup of the group of units,
whereas `nthRoots` is a multiset. -/
def rootsOfUnityEquivNthRoots : rootsOfUnity k R ≃ { x // x ∈ nthRoots k (1 : R) } := by
  refine'
    { toFun := fun x => ⟨(x : Rˣ), mem_rootsOfUnity_iff_mem_nthRoots.mp x.2⟩
      invFun := fun x => ⟨⟨x, ↑x ^ (k - 1 : ℕ), _, _⟩, _⟩
      left_inv := _
      right_inv := _ }
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  all_goals
    rcases x with ⟨x, hx⟩; rw [mem_nthRoots k.pos] at hx
    

Proof state:
case refine'_2.mk
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✝¹ : CommRing R
inst✝ : IsDomain R
x : R
hx✝ : x ∈ nthRoots (↑k) 1
hx : x ^ ↑k = 1
⊢ ↑{ val := x, property := hx✝ } ^ (↑k - 1) * ↑{ val := x, property := hx✝ } = 1

Next tactic:
simp only [Subtype.coe_mk, ← pow_succ, ← pow_succ', hx,
      tsub_add_cancel_of_le (show 1 ≤ (k : ℕ) from k.one_le)]
/-- Equivalence between the `k`-th roots of unity in `R` and the `k`-th roots of `1`.

This is implemented as equivalence of subtypes,
because `rootsOfUnity` is a subgroup of the group of units,
whereas `nthRoots` is a multiset. -/
def rootsOfUnityEquivNthRoots : rootsOfUnity k R ≃ { x // x ∈ nthRoots k (1 : R) } := by
  refine'
    { toFun := fun x => ⟨(x : Rˣ), mem_rootsOfUnity_iff_mem_nthRoots.mp x.2⟩
      invFun := fun x => ⟨⟨x, ↑x ^ (k - 1 : ℕ), _, _⟩, _⟩
      left_inv := _
      right_inv := _ }
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  all_goals
    

Proof state:
case refine'_3
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✝¹ : CommRing R
inst✝ : IsDomain R
x : { x // x ∈ nthRoots (↑k) 1 }
⊢ { val := ↑x, inv := ↑x ^ (↑k - 1), val_inv := (_ : ↑x * ↑x ^ (↑k - 1) = 1),
      inv_val := (_ : ↑x ^ (↑k - 1) * ↑x = 1) } ∈
    rootsOfUnity k R

Next tactic:
rcases x with ⟨x, hx⟩
/-- Equivalence between the `k`-th roots of unity in `R` and the `k`-th roots of `1`.

This is implemented as equivalence of subtypes,
because `rootsOfUnity` is a subgroup of the group of units,
whereas `nthRoots` is a multiset. -/
def rootsOfUnityEquivNthRoots : rootsOfUnity k R ≃ { x // x ∈ nthRoots k (1 : R) } := by
  refine'
    { toFun := fun x => ⟨(x : Rˣ), mem_rootsOfUnity_iff_mem_nthRoots.mp x.2⟩
      invFun := fun x => ⟨⟨x, ↑x ^ (k - 1 : ℕ), _, _⟩, _⟩
      left_inv := _
      right_inv := _ }
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  all_goals
    rcases x with ⟨x, hx⟩; 

Proof state:
case refine'_3.mk
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✝¹ : CommRing R
inst✝ : IsDomain R
x : R
hx : x ∈ nthRoots (↑k) 1
⊢ { val := ↑{ val := x, property := hx }, inv := ↑{ val := x, property := hx } ^ (↑k - 1),
      val_inv := (_ : ↑{ val := x, property := hx } * ↑{ val := x, property := hx } ^ (↑k - 1) = 1),
      inv_val := (_ : ↑{ val := x, property := hx } ^ (↑k - 1) * ↑{ val := x, property := hx } = 1) } ∈
    rootsOfUnity k R

Next tactic:
rw [mem_nthRoots k.pos] at hx
/-- Equivalence between the `k`-th roots of unity in `R` and the `k`-th roots of `1`.

This is implemented as equivalence of subtypes,
because `rootsOfUnity` is a subgroup of the group of units,
whereas `nthRoots` is a multiset. -/
def rootsOfUnityEquivNthRoots : rootsOfUnity k R ≃ { x // x ∈ nthRoots k (1 : R) } := by
  refine'
    { toFun := fun x => ⟨(x : Rˣ), mem_rootsOfUnity_iff_mem_nthRoots.mp x.2⟩
      invFun := fun x => ⟨⟨x, ↑x ^ (k - 1 : ℕ), _, _⟩, _⟩
      left_inv := _
      right_inv := _ }
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  all_goals
    rcases x with ⟨x, hx⟩; rw [mem_nthRoots k.pos] at hx
    

Proof state:
case refine'_3.mk
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✝¹ : CommRing R
inst✝ : IsDomain R
x : R
hx✝ : x ∈ nthRoots (↑k) 1
hx : x ^ ↑k = 1
⊢ { val := ↑{ val := x, property := hx✝ }, inv := ↑{ val := x, property := hx✝ } ^ (↑k - 1),
      val_inv := (_ : ↑{ val := x, property := hx✝ } * ↑{ val := x, property := hx✝ } ^ (↑k - 1) = 1),
      inv_val := (_ : ↑{ val := x, property := hx✝ } ^ (↑k - 1) * ↑{ val := x, property := hx✝ } = 1) } ∈
    rootsOfUnity k R

Next tactic:
simp only [Subtype.coe_mk, ← pow_succ, ← pow_succ', hx,
      tsub_add_cancel_of_le (show 1 ≤ (k : ℕ) from k.one_le)]
/-- Equivalence between the `k`-th roots of unity in `R` and the `k`-th roots of `1`.

This is implemented as equivalence of subtypes,
because `rootsOfUnity` is a subgroup of the group of units,
whereas `nthRoots` is a multiset. -/
def rootsOfUnityEquivNthRoots : rootsOfUnity k R ≃ { x // x ∈ nthRoots k (1 : R) } := by
  refine'
    { toFun := fun x => ⟨(x : Rˣ), mem_rootsOfUnity_iff_mem_nthRoots.mp x.2⟩
      invFun := fun x => ⟨⟨x, ↑x ^ (k - 1 : ℕ), _, _⟩, _⟩
      left_inv := _
      right_inv := _ }
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  all_goals
    rcases x with ⟨x, hx⟩; rw [mem_nthRoots k.pos] at hx
    simp only [Subtype.coe_mk, ← pow_succ, ← pow_succ', hx,
      tsub_add_cancel_of_le (show 1 ≤ (k : ℕ) from k.one_le)]
  · 

Proof state:
case refine'_3.mk
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✝¹ : CommRing R
inst✝ : IsDomain R
x : R
hx✝ : x ∈ nthRoots (↑k) 1
hx : x ^ ↑k = 1
⊢ { val := x, inv := x ^ (↑k - 1),
      val_inv := (_ : ↑{ val := x, property := hx✝ } * ↑{ val := x, property := hx✝ } ^ (↑k - 1) = 1),
      inv_val := (_ : ↑{ val := x, property := hx✝ } ^ (↑k - 1) * ↑{ val := x, property := hx✝ } = 1) } ∈
    rootsOfUnity k R

Next tactic:
show (_ : Rˣ) ^ (k : ℕ) = 1
/-- Equivalence between the `k`-th roots of unity in `R` and the `k`-th roots of `1`.

This is implemented as equivalence of subtypes,
because `rootsOfUnity` is a subgroup of the group of units,
whereas `nthRoots` is a multiset. -/
def rootsOfUnityEquivNthRoots : rootsOfUnity k R ≃ { x // x ∈ nthRoots k (1 : R) } := by
  refine'
    { toFun := fun x => ⟨(x : Rˣ), mem_rootsOfUnity_iff_mem_nthRoots.mp x.2⟩
      invFun := fun x => ⟨⟨x, ↑x ^ (k - 1 : ℕ), _, _⟩, _⟩
      left_inv := _
      right_inv := _ }
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  pick_goal 4; · rintro ⟨x, hx⟩; ext; rfl
  all_goals
    rcases x with ⟨x, hx⟩; rw [mem_nthRoots k.pos] at hx
    simp only [Subtype.coe_mk, ← pow_succ, ← pow_succ', hx,
      tsub_add_cancel_of_le (show 1 ≤ (k : ℕ) from k.one_le)]
  · show (_ : Rˣ) ^ (k : ℕ) = 1
    

Proof state:
case refine'_3.mk
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✝¹ : CommRing R
inst✝ : IsDomain R
x : R
hx✝ : x ∈ nthRoots (↑k) 1
hx : x ^ ↑k = 1
⊢ { val := x, inv := x ^ (↑k - 1),
        val_inv := (_ : ↑{ val := x, property := hx✝ } * ↑{ val := x, property := hx✝ } ^ (↑k - 1) = 1),
        inv_val := (_ : ↑{ val := x, property := hx✝ } ^ (↑k - 1) * ↑{ val := x, property := hx✝ } = 1) } ^
      ↑k =
    1

Next tactic:
simp only [Units.ext_iff, hx, Units.val_mk, Units.val_one, Subtype.coe_mk,
      Units.val_pow_eq_pow_val]
theorem map_rootsOfUnity_eq_pow_self [RingHomClass F R R] (σ : F) (ζ : rootsOfUnity k R) :
    ∃ m : ℕ, σ (ζ : 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✝² : CommRing R
inst✝¹ : IsDomain R
inst✝ : RingHomClass F R R
σ : F
ζ : ↥(rootsOfUnity k R)
⊢ ∃ m, σ ↑↑ζ = ↑↑ζ ^ m

Next tactic:
obtain ⟨m, hm⟩ := MonoidHom.map_cyclic (restrictRootsOfUnity σ k)
theorem map_rootsOfUnity_eq_pow_self [RingHomClass F R R] (σ : F) (ζ : rootsOfUnity k R) :
    ∃ m : ℕ, σ (ζ : Rˣ) = ((ζ : Rˣ) : R) ^ m := by
  obtain ⟨m, hm⟩ := MonoidHom.map_cyclic (restrictRootsOfUnity σ k)
  

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 l : ℕ+
inst✝² : CommRing R
inst✝¹ : IsDomain R
inst✝ : RingHomClass F R R
σ : F
ζ : ↥(rootsOfUnity k R)
m : ℤ
hm : ∀ (g : ↥(rootsOfUnity k R)), (restrictRootsOfUnity σ k) g = g ^ m
⊢ ∃ m, σ ↑↑ζ = ↑↑ζ ^ m

Next tactic:
rw [← restrictRootsOfUnity_coe_apply, hm, ← zpow_mod_orderOf, ← Int.toNat_of_nonneg
      (m.emod_nonneg (Int.coe_nat_ne_zero.mpr (pos_iff_ne_zero.mp (orderOf_pos ζ)))),
    zpow_ofNat, rootsOfUnity.coe_pow]