l3lab/ntp-mathlib huggingface dataset:
/-- **Noether's second isomorphism theorem**: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(HN)/N`. -/
@[to_additive "The second isomorphism theorem: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(H + N)/N`"]
noncomputable def quotientInfEquivProdNormalQuotient (H N : Subgroup G) [N.Normal] :
    H ⧸ N.subgroupOf H ≃* _ ⧸ N.subgroupOf (H ⊔ N) :=
  let
    φ :-- φ is the natural homomorphism H →* (HN)/N.
      H →*
      _ ⧸ N.subgroupOf (H ⊔ N) :=
    (mk' <| N.subgroupOf (H ⊔ N)).comp (inclusion le_sup_left)
  have φ_surjective : Surjective φ := fun x =>
    x.inductionOn' <| by
      rintro ⟨y, hy : y ∈ (H ⊔ N)⟩;
      

Proof state:
case mk
G : Type u
inst✝³ : Group G
N✝ : Subgroup G
nN : Normal N✝
H✝ : Type v
inst✝² : Group H✝
M : Type x
inst✝¹ : Monoid M
φ✝ : G →* H✝
H N : Subgroup G
inst✝ : Normal N
φ : ↥H →* ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N) := MonoidHom.comp (mk' (subgroupOf N (H ⊔ N))) (inclusion (_ : H ≤ H ⊔ N))
x : ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N)
y : G
hy : y ∈ H ⊔ N
⊢ ∃ a, φ a = Quotient.mk'' { val := y, property := hy }

Next tactic:
rw [← SetLike.mem_coe] at hy
/-- **Noether's second isomorphism theorem**: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(HN)/N`. -/
@[to_additive "The second isomorphism theorem: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(H + N)/N`"]
noncomputable def quotientInfEquivProdNormalQuotient (H N : Subgroup G) [N.Normal] :
    H ⧸ N.subgroupOf H ≃* _ ⧸ N.subgroupOf (H ⊔ N) :=
  let
    φ :-- φ is the natural homomorphism H →* (HN)/N.
      H →*
      _ ⧸ N.subgroupOf (H ⊔ N) :=
    (mk' <| N.subgroupOf (H ⊔ N)).comp (inclusion le_sup_left)
  have φ_surjective : Surjective φ := fun x =>
    x.inductionOn' <| by
      rintro ⟨y, hy : y ∈ (H ⊔ N)⟩;
      rw [← SetLike.mem_coe] at hy
      

Proof state:
case mk
G : Type u
inst✝³ : Group G
N✝ : Subgroup G
nN : Normal N✝
H✝ : Type v
inst✝² : Group H✝
M : Type x
inst✝¹ : Monoid M
φ✝ : G →* H✝
H N : Subgroup G
inst✝ : Normal N
φ : ↥H →* ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N) := MonoidHom.comp (mk' (subgroupOf N (H ⊔ N))) (inclusion (_ : H ≤ H ⊔ N))
x : ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N)
y : G
hy✝ : y ∈ H ⊔ N
hy : y ∈ ↑(H ⊔ N)
⊢ ∃ a, φ a = Quotient.mk'' { val := y, property := hy✝ }

Next tactic:
rw [mul_normal H N] at hy
/-- **Noether's second isomorphism theorem**: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(HN)/N`. -/
@[to_additive "The second isomorphism theorem: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(H + N)/N`"]
noncomputable def quotientInfEquivProdNormalQuotient (H N : Subgroup G) [N.Normal] :
    H ⧸ N.subgroupOf H ≃* _ ⧸ N.subgroupOf (H ⊔ N) :=
  let
    φ :-- φ is the natural homomorphism H →* (HN)/N.
      H →*
      _ ⧸ N.subgroupOf (H ⊔ N) :=
    (mk' <| N.subgroupOf (H ⊔ N)).comp (inclusion le_sup_left)
  have φ_surjective : Surjective φ := fun x =>
    x.inductionOn' <| by
      rintro ⟨y, hy : y ∈ (H ⊔ N)⟩;
      rw [← SetLike.mem_coe] at hy
      rw [mul_normal H N] at hy
      

Proof state:
case mk
G : Type u
inst✝³ : Group G
N✝ : Subgroup G
nN : Normal N✝
H✝ : Type v
inst✝² : Group H✝
M : Type x
inst✝¹ : Monoid M
φ✝ : G →* H✝
H N : Subgroup G
inst✝ : Normal N
φ : ↥H →* ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N) := MonoidHom.comp (mk' (subgroupOf N (H ⊔ N))) (inclusion (_ : H ≤ H ⊔ N))
x : ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N)
y : G
hy✝ : y ∈ H ⊔ N
hy : y ∈ ↑H * ↑N
⊢ ∃ a, φ a = Quotient.mk'' { val := y, property := hy✝ }

Next tactic:
rcases hy with ⟨h, n, hh, hn, rfl⟩
/-- **Noether's second isomorphism theorem**: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(HN)/N`. -/
@[to_additive "The second isomorphism theorem: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(H + N)/N`"]
noncomputable def quotientInfEquivProdNormalQuotient (H N : Subgroup G) [N.Normal] :
    H ⧸ N.subgroupOf H ≃* _ ⧸ N.subgroupOf (H ⊔ N) :=
  let
    φ :-- φ is the natural homomorphism H →* (HN)/N.
      H →*
      _ ⧸ N.subgroupOf (H ⊔ N) :=
    (mk' <| N.subgroupOf (H ⊔ N)).comp (inclusion le_sup_left)
  have φ_surjective : Surjective φ := fun x =>
    x.inductionOn' <| by
      rintro ⟨y, hy : y ∈ (H ⊔ N)⟩;
      rw [← SetLike.mem_coe] at hy
      rw [mul_normal H N] at hy
      rcases hy with ⟨h, n, hh, hn, rfl⟩
      

Proof state:
case mk.intro.intro.intro.intro
G : Type u
inst✝³ : Group G
N✝ : Subgroup G
nN : Normal N✝
H✝ : Type v
inst✝² : Group H✝
M : Type x
inst✝¹ : Monoid M
φ✝ : G →* H✝
H N : Subgroup G
inst✝ : Normal N
φ : ↥H →* ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N) := MonoidHom.comp (mk' (subgroupOf N (H ⊔ N))) (inclusion (_ : H ≤ H ⊔ N))
x : ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N)
h n : G
hh : h ∈ ↑H
hn : n ∈ ↑N
hy : (fun x x_1 => x * x_1) h n ∈ H ⊔ N
⊢ ∃ a, φ a = Quotient.mk'' { val := (fun x x_1 => x * x_1) h n, property := hy }

Next tactic:
use ⟨h, hh⟩
/-- **Noether's second isomorphism theorem**: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(HN)/N`. -/
@[to_additive "The second isomorphism theorem: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(H + N)/N`"]
noncomputable def quotientInfEquivProdNormalQuotient (H N : Subgroup G) [N.Normal] :
    H ⧸ N.subgroupOf H ≃* _ ⧸ N.subgroupOf (H ⊔ N) :=
  let
    φ :-- φ is the natural homomorphism H →* (HN)/N.
      H →*
      _ ⧸ N.subgroupOf (H ⊔ N) :=
    (mk' <| N.subgroupOf (H ⊔ N)).comp (inclusion le_sup_left)
  have φ_surjective : Surjective φ := fun x =>
    x.inductionOn' <| by
      rintro ⟨y, hy : y ∈ (H ⊔ N)⟩;
      rw [← SetLike.mem_coe] at hy
      rw [mul_normal H N] at hy
      rcases hy with ⟨h, n, hh, hn, rfl⟩
      use ⟨h, hh⟩
      

Proof state:
case h
G : Type u
inst✝³ : Group G
N✝ : Subgroup G
nN : Normal N✝
H✝ : Type v
inst✝² : Group H✝
M : Type x
inst✝¹ : Monoid M
φ✝ : G →* H✝
H N : Subgroup G
inst✝ : Normal N
φ : ↥H →* ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N) := MonoidHom.comp (mk' (subgroupOf N (H ⊔ N))) (inclusion (_ : H ≤ H ⊔ N))
x : ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N)
h n : G
hh : h ∈ ↑H
hn : n ∈ ↑N
hy : (fun x x_1 => x * x_1) h n ∈ H ⊔ N
⊢ φ { val := h, property := hh } = Quotient.mk'' { val := (fun x x_1 => x * x_1) h n, property := hy }

Next tactic:
let _ : Setoid ↑(H ⊔ N) :=
        (@leftRel ↑(H ⊔ N) (H ⊔ N : Subgroup G).toGroup (N.subgroupOf (H ⊔ N)))
/-- **Noether's second isomorphism theorem**: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(HN)/N`. -/
@[to_additive "The second isomorphism theorem: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(H + N)/N`"]
noncomputable def quotientInfEquivProdNormalQuotient (H N : Subgroup G) [N.Normal] :
    H ⧸ N.subgroupOf H ≃* _ ⧸ N.subgroupOf (H ⊔ N) :=
  let
    φ :-- φ is the natural homomorphism H →* (HN)/N.
      H →*
      _ ⧸ N.subgroupOf (H ⊔ N) :=
    (mk' <| N.subgroupOf (H ⊔ N)).comp (inclusion le_sup_left)
  have φ_surjective : Surjective φ := fun x =>
    x.inductionOn' <| by
      rintro ⟨y, hy : y ∈ (H ⊔ N)⟩;
      rw [← SetLike.mem_coe] at hy
      rw [mul_normal H N] at hy
      rcases hy with ⟨h, n, hh, hn, rfl⟩
      use ⟨h, hh⟩
      let _ : Setoid ↑(H ⊔ N) :=
        (@leftRel ↑(H ⊔ N) (H ⊔ N : Subgroup G).toGroup (N.subgroupOf (H ⊔ N)))
      -- porting note: Lean couldn't find this automatically
      

Proof state:
case h
G : Type u
inst✝³ : Group G
N✝ : Subgroup G
nN : Normal N✝
H✝ : Type v
inst✝² : Group H✝
M : Type x
inst✝¹ : Monoid M
φ✝ : G →* H✝
H N : Subgroup G
inst✝ : Normal N
φ : ↥H →* ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N) := MonoidHom.comp (mk' (subgroupOf N (H ⊔ N))) (inclusion (_ : H ≤ H ⊔ N))
x : ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N)
h n : G
hh : h ∈ ↑H
hn : n ∈ ↑N
hy : (fun x x_1 => x * x_1) h n ∈ H ⊔ N
x✝ : Setoid ↥(H ⊔ N) := leftRel (subgroupOf N (H ⊔ N))
⊢ φ { val := h, property := hh } = Quotient.mk'' { val := (fun x x_1 => x * x_1) h n, property := hy }

Next tactic:
refine Quotient.eq.mpr ?_
/-- **Noether's second isomorphism theorem**: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(HN)/N`. -/
@[to_additive "The second isomorphism theorem: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(H + N)/N`"]
noncomputable def quotientInfEquivProdNormalQuotient (H N : Subgroup G) [N.Normal] :
    H ⧸ N.subgroupOf H ≃* _ ⧸ N.subgroupOf (H ⊔ N) :=
  let
    φ :-- φ is the natural homomorphism H →* (HN)/N.
      H →*
      _ ⧸ N.subgroupOf (H ⊔ N) :=
    (mk' <| N.subgroupOf (H ⊔ N)).comp (inclusion le_sup_left)
  have φ_surjective : Surjective φ := fun x =>
    x.inductionOn' <| by
      rintro ⟨y, hy : y ∈ (H ⊔ N)⟩;
      rw [← SetLike.mem_coe] at hy
      rw [mul_normal H N] at hy
      rcases hy with ⟨h, n, hh, hn, rfl⟩
      use ⟨h, hh⟩
      let _ : Setoid ↑(H ⊔ N) :=
        (@leftRel ↑(H ⊔ N) (H ⊔ N : Subgroup G).toGroup (N.subgroupOf (H ⊔ N)))
      -- porting note: Lean couldn't find this automatically
      refine Quotient.eq.mpr ?_
      

Proof state:
case h
G : Type u
inst✝³ : Group G
N✝ : Subgroup G
nN : Normal N✝
H✝ : Type v
inst✝² : Group H✝
M : Type x
inst✝¹ : Monoid M
φ✝ : G →* H✝
H N : Subgroup G
inst✝ : Normal N
φ : ↥H →* ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N) := MonoidHom.comp (mk' (subgroupOf N (H ⊔ N))) (inclusion (_ : H ≤ H ⊔ N))
x : ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N)
h n : G
hh : h ∈ ↑H
hn : n ∈ ↑N
hy : (fun x x_1 => x * x_1) h n ∈ H ⊔ N
x✝ : Setoid ↥(H ⊔ N) := leftRel (subgroupOf N (H ⊔ N))
⊢ (inclusion (_ : H ≤ H ⊔ N)) { val := h, property := hh } ≈ { val := (fun x x_1 => x * x_1) h n, property := hy }

Next tactic:
change Setoid.r _ _
/-- **Noether's second isomorphism theorem**: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(HN)/N`. -/
@[to_additive "The second isomorphism theorem: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(H + N)/N`"]
noncomputable def quotientInfEquivProdNormalQuotient (H N : Subgroup G) [N.Normal] :
    H ⧸ N.subgroupOf H ≃* _ ⧸ N.subgroupOf (H ⊔ N) :=
  let
    φ :-- φ is the natural homomorphism H →* (HN)/N.
      H →*
      _ ⧸ N.subgroupOf (H ⊔ N) :=
    (mk' <| N.subgroupOf (H ⊔ N)).comp (inclusion le_sup_left)
  have φ_surjective : Surjective φ := fun x =>
    x.inductionOn' <| by
      rintro ⟨y, hy : y ∈ (H ⊔ N)⟩;
      rw [← SetLike.mem_coe] at hy
      rw [mul_normal H N] at hy
      rcases hy with ⟨h, n, hh, hn, rfl⟩
      use ⟨h, hh⟩
      let _ : Setoid ↑(H ⊔ N) :=
        (@leftRel ↑(H ⊔ N) (H ⊔ N : Subgroup G).toGroup (N.subgroupOf (H ⊔ N)))
      -- porting note: Lean couldn't find this automatically
      refine Quotient.eq.mpr ?_
      change Setoid.r _ _
      

Proof state:
case h
G : Type u
inst✝³ : Group G
N✝ : Subgroup G
nN : Normal N✝
H✝ : Type v
inst✝² : Group H✝
M : Type x
inst✝¹ : Monoid M
φ✝ : G →* H✝
H N : Subgroup G
inst✝ : Normal N
φ : ↥H →* ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N) := MonoidHom.comp (mk' (subgroupOf N (H ⊔ N))) (inclusion (_ : H ≤ H ⊔ N))
x : ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N)
h n : G
hh : h ∈ ↑H
hn : n ∈ ↑N
hy : (fun x x_1 => x * x_1) h n ∈ H ⊔ N
x✝ : Setoid ↥(H ⊔ N) := leftRel (subgroupOf N (H ⊔ N))
⊢ Setoid.r ((inclusion (_ : H ≤ H ⊔ N)) { val := h, property := hh })
    { val := (fun x x_1 => x * x_1) h n, property := hy }

Next tactic:
rw [leftRel_apply]
/-- **Noether's second isomorphism theorem**: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(HN)/N`. -/
@[to_additive "The second isomorphism theorem: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(H + N)/N`"]
noncomputable def quotientInfEquivProdNormalQuotient (H N : Subgroup G) [N.Normal] :
    H ⧸ N.subgroupOf H ≃* _ ⧸ N.subgroupOf (H ⊔ N) :=
  let
    φ :-- φ is the natural homomorphism H →* (HN)/N.
      H →*
      _ ⧸ N.subgroupOf (H ⊔ N) :=
    (mk' <| N.subgroupOf (H ⊔ N)).comp (inclusion le_sup_left)
  have φ_surjective : Surjective φ := fun x =>
    x.inductionOn' <| by
      rintro ⟨y, hy : y ∈ (H ⊔ N)⟩;
      rw [← SetLike.mem_coe] at hy
      rw [mul_normal H N] at hy
      rcases hy with ⟨h, n, hh, hn, rfl⟩
      use ⟨h, hh⟩
      let _ : Setoid ↑(H ⊔ N) :=
        (@leftRel ↑(H ⊔ N) (H ⊔ N : Subgroup G).toGroup (N.subgroupOf (H ⊔ N)))
      -- porting note: Lean couldn't find this automatically
      refine Quotient.eq.mpr ?_
      change Setoid.r _ _
      rw [leftRel_apply]
      

Proof state:
case h
G : Type u
inst✝³ : Group G
N✝ : Subgroup G
nN : Normal N✝
H✝ : Type v
inst✝² : Group H✝
M : Type x
inst✝¹ : Monoid M
φ✝ : G →* H✝
H N : Subgroup G
inst✝ : Normal N
φ : ↥H →* ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N) := MonoidHom.comp (mk' (subgroupOf N (H ⊔ N))) (inclusion (_ : H ≤ H ⊔ N))
x : ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N)
h n : G
hh : h ∈ ↑H
hn : n ∈ ↑N
hy : (fun x x_1 => x * x_1) h n ∈ H ⊔ N
x✝ : Setoid ↥(H ⊔ N) := leftRel (subgroupOf N (H ⊔ N))
⊢ ((inclusion (_ : H ≤ H ⊔ N)) { val := h, property := hh })⁻¹ * { val := (fun x x_1 => x * x_1) h n, property := hy } ∈
    subgroupOf N (H ⊔ N)

Next tactic:
change h⁻¹ * (h * n) ∈ N
/-- **Noether's second isomorphism theorem**: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(HN)/N`. -/
@[to_additive "The second isomorphism theorem: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(H + N)/N`"]
noncomputable def quotientInfEquivProdNormalQuotient (H N : Subgroup G) [N.Normal] :
    H ⧸ N.subgroupOf H ≃* _ ⧸ N.subgroupOf (H ⊔ N) :=
  let
    φ :-- φ is the natural homomorphism H →* (HN)/N.
      H →*
      _ ⧸ N.subgroupOf (H ⊔ N) :=
    (mk' <| N.subgroupOf (H ⊔ N)).comp (inclusion le_sup_left)
  have φ_surjective : Surjective φ := fun x =>
    x.inductionOn' <| by
      rintro ⟨y, hy : y ∈ (H ⊔ N)⟩;
      rw [← SetLike.mem_coe] at hy
      rw [mul_normal H N] at hy
      rcases hy with ⟨h, n, hh, hn, rfl⟩
      use ⟨h, hh⟩
      let _ : Setoid ↑(H ⊔ N) :=
        (@leftRel ↑(H ⊔ N) (H ⊔ N : Subgroup G).toGroup (N.subgroupOf (H ⊔ N)))
      -- porting note: Lean couldn't find this automatically
      refine Quotient.eq.mpr ?_
      change Setoid.r _ _
      rw [leftRel_apply]
      change h⁻¹ * (h * n) ∈ N
      

Proof state:
case h
G : Type u
inst✝³ : Group G
N✝ : Subgroup G
nN : Normal N✝
H✝ : Type v
inst✝² : Group H✝
M : Type x
inst✝¹ : Monoid M
φ✝ : G →* H✝
H N : Subgroup G
inst✝ : Normal N
φ : ↥H →* ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N) := MonoidHom.comp (mk' (subgroupOf N (H ⊔ N))) (inclusion (_ : H ≤ H ⊔ N))
x : ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N)
h n : G
hh : h ∈ ↑H
hn : n ∈ ↑N
hy : (fun x x_1 => x * x_1) h n ∈ H ⊔ N
x✝ : Setoid ↥(H ⊔ N) := leftRel (subgroupOf N (H ⊔ N))
⊢ h⁻¹ * (h * n) ∈ N

Next tactic:
rwa [← mul_assoc, inv_mul_self, one_mul]
/-- **Noether's second isomorphism theorem**: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(HN)/N`. -/
@[to_additive "The second isomorphism theorem: given two subgroups `H` and `N` of a group `G`, where
`N` is normal, defines an isomorphism between `H/(H ∩ N)` and `(H + N)/N`"]
noncomputable def quotientInfEquivProdNormalQuotient (H N : Subgroup G) [N.Normal] :
    H ⧸ N.subgroupOf H ≃* _ ⧸ N.subgroupOf (H ⊔ N) :=
  let
    φ :-- φ is the natural homomorphism H →* (HN)/N.
      H →*
      _ ⧸ N.subgroupOf (H ⊔ N) :=
    (mk' <| N.subgroupOf (H ⊔ N)).comp (inclusion le_sup_left)
  have φ_surjective : Surjective φ := fun x =>
    x.inductionOn' <| by
      rintro ⟨y, hy : y ∈ (H ⊔ N)⟩;
      rw [← SetLike.mem_coe] at hy
      rw [mul_normal H N] at hy
      rcases hy with ⟨h, n, hh, hn, rfl⟩
      use ⟨h, hh⟩
      let _ : Setoid ↑(H ⊔ N) :=
        (@leftRel ↑(H ⊔ N) (H ⊔ N : Subgroup G).toGroup (N.subgroupOf (H ⊔ N)))
      -- porting note: Lean couldn't find this automatically
      refine Quotient.eq.mpr ?_
      change Setoid.r _ _
      rw [leftRel_apply]
      change h⁻¹ * (h * n) ∈ N
      rwa [← mul_assoc, inv_mul_self, one_mul]
  (quotientMulEquivOfEq (by 

Proof state:
G : Type u
inst✝³ : Group G
N✝ : Subgroup G
nN : Normal N✝
H✝ : Type v
inst✝² : Group H✝
M : Type x
inst✝¹ : Monoid M
φ✝ : G →* H✝
H N : Subgroup G
inst✝ : Normal N
φ : ↥H →* ↥(H ⊔ N) ⧸ subgroupOf N (H ⊔ N) := MonoidHom.comp (mk' (subgroupOf N (H ⊔ N))) (inclusion (_ : H ≤ H ⊔ N))
φ_surjective : Surjective ⇑φ
⊢ subgroupOf N H = ker φ

Next tactic:
simp [← comap_ker]
/-- The map from the third isomorphism theorem for groups: `(G / N) / (M / N) → G / M`. -/
@[to_additive "The map from the third isomorphism theorem for additive groups:
`(A / N) / (M / N) → A / M`."]
def quotientQuotientEquivQuotientAux : (G ⧸ N) ⧸ M.map (mk' N) →* G ⧸ M :=
  lift (M.map (mk' N)) (map N M (MonoidHom.id G) h)
    (by
      

Proof state:
G : Type u
inst✝² : Group G
N : Subgroup G
nN : Subgroup.Normal N
H : Type v
inst✝¹ : Group H
M✝ : Type x
inst✝ : Monoid M✝
φ : G →* H
M : Subgroup G
nM : Subgroup.Normal M
h : N ≤ M
⊢ Subgroup.map (mk' N) M ≤ ker (map N M (MonoidHom.id G) h)

Next tactic:
rintro _ ⟨x, hx, rfl⟩
/-- The map from the third isomorphism theorem for groups: `(G / N) / (M / N) → G / M`. -/
@[to_additive "The map from the third isomorphism theorem for additive groups:
`(A / N) / (M / N) → A / M`."]
def quotientQuotientEquivQuotientAux : (G ⧸ N) ⧸ M.map (mk' N) →* G ⧸ M :=
  lift (M.map (mk' N)) (map N M (MonoidHom.id G) h)
    (by
      rintro _ ⟨x, hx, rfl⟩
      

Proof state:
case intro.intro
G : Type u
inst✝² : Group G
N : Subgroup G
nN : Subgroup.Normal N
H : Type v
inst✝¹ : Group H
M✝ : Type x
inst✝ : Monoid M✝
φ : G →* H
M : Subgroup G
nM : Subgroup.Normal M
h : N ≤ M
x : G
hx : x ∈ ↑M
⊢ (mk' N) x ∈ ker (map N M (MonoidHom.id G) h)

Next tactic:
rw [mem_ker, map_mk' N M _ _ x]
/-- The map from the third isomorphism theorem for groups: `(G / N) / (M / N) → G / M`. -/
@[to_additive "The map from the third isomorphism theorem for additive groups:
`(A / N) / (M / N) → A / M`."]
def quotientQuotientEquivQuotientAux : (G ⧸ N) ⧸ M.map (mk' N) →* G ⧸ M :=
  lift (M.map (mk' N)) (map N M (MonoidHom.id G) h)
    (by
      rintro _ ⟨x, hx, rfl⟩
      rw [mem_ker, map_mk' N M _ _ x]
      

Proof state:
case intro.intro
G : Type u
inst✝² : Group G
N : Subgroup G
nN : Subgroup.Normal N
H : Type v
inst✝¹ : Group H
M✝ : Type x
inst✝ : Monoid M✝
φ : G →* H
M : Subgroup G
nM : Subgroup.Normal M
h : N ≤ M
x : G
hx : x ∈ ↑M
⊢ ↑((MonoidHom.id G) x) = 1

Next tactic:
exact (QuotientGroup.eq_one_iff _).mpr hx
/-- **Noether's third isomorphism theorem** for groups: `(G / N) / (M / N) ≃* G / M`. -/
@[to_additive
      "**Noether's third isomorphism theorem** for additive groups: `(A / N) / (M / N) ≃+ A / M`."]
def quotientQuotientEquivQuotient : (G ⧸ N) ⧸ M.map (QuotientGroup.mk' N) ≃* G ⧸ M :=
  MonoidHom.toMulEquiv (quotientQuotientEquivQuotientAux N M h)
    (QuotientGroup.map _ _ (QuotientGroup.mk' N) (Subgroup.le_comap_map _ _))
    (by 

Proof state:
G : Type u
inst✝² : Group G
N : Subgroup G
nN : Subgroup.Normal N
H : Type v
inst✝¹ : Group H
M✝ : Type x
inst✝ : Monoid M✝
φ : G →* H
M : Subgroup G
nM : Subgroup.Normal M
h : N ≤ M
⊢ MonoidHom.comp (map M (Subgroup.map (mk' N) M) (mk' N) (_ : M ≤ Subgroup.comap (mk' N) (Subgroup.map (mk' N) M)))
      (quotientQuotientEquivQuotientAux N M h) =
    MonoidHom.id ((G ⧸ N) ⧸ Subgroup.map (mk' N) M)

Next tactic:
ext
/-- **Noether's third isomorphism theorem** for groups: `(G / N) / (M / N) ≃* G / M`. -/
@[to_additive
      "**Noether's third isomorphism theorem** for additive groups: `(A / N) / (M / N) ≃+ A / M`."]
def quotientQuotientEquivQuotient : (G ⧸ N) ⧸ M.map (QuotientGroup.mk' N) ≃* G ⧸ M :=
  MonoidHom.toMulEquiv (quotientQuotientEquivQuotientAux N M h)
    (QuotientGroup.map _ _ (QuotientGroup.mk' N) (Subgroup.le_comap_map _ _))
    (by ext; 

Proof state:
case h.h.h
G : Type u
inst✝² : Group G
N : Subgroup G
nN : Subgroup.Normal N
H : Type v
inst✝¹ : Group H
M✝ : Type x
inst✝ : Monoid M✝
φ : G →* H
M : Subgroup G
nM : Subgroup.Normal M
h : N ≤ M
x✝ : G
⊢ (MonoidHom.comp
        (MonoidHom.comp
          (MonoidHom.comp
            (map M (Subgroup.map (mk' N) M) (mk' N) (_ : M ≤ Subgroup.comap (mk' N) (Subgroup.map (mk' N) M)))
            (quotientQuotientEquivQuotientAux N M h))
          (mk' (Subgroup.map (mk' N) M)))
        (mk' N))
      x✝ =
    (MonoidHom.comp (MonoidHom.comp (MonoidHom.id ((G ⧸ N) ⧸ Subgroup.map (mk' N) M)) (mk' (Subgroup.map (mk' N) M)))
        (mk' N))
      x✝

Next tactic:
simp
/-- **Noether's third isomorphism theorem** for groups: `(G / N) / (M / N) ≃* G / M`. -/
@[to_additive
      "**Noether's third isomorphism theorem** for additive groups: `(A / N) / (M / N) ≃+ A / M`."]
def quotientQuotientEquivQuotient : (G ⧸ N) ⧸ M.map (QuotientGroup.mk' N) ≃* G ⧸ M :=
  MonoidHom.toMulEquiv (quotientQuotientEquivQuotientAux N M h)
    (QuotientGroup.map _ _ (QuotientGroup.mk' N) (Subgroup.le_comap_map _ _))
    (by ext; simp)
    (by 

Proof state:
G : Type u
inst✝² : Group G
N : Subgroup G
nN : Subgroup.Normal N
H : Type v
inst✝¹ : Group H
M✝ : Type x
inst✝ : Monoid M✝
φ : G →* H
M : Subgroup G
nM : Subgroup.Normal M
h : N ≤ M
⊢ MonoidHom.comp (quotientQuotientEquivQuotientAux N M h)
      (map M (Subgroup.map (mk' N) M) (mk' N) (_ : M ≤ Subgroup.comap (mk' N) (Subgroup.map (mk' N) M))) =
    MonoidHom.id (G ⧸ M)

Next tactic:
ext
/-- **Noether's third isomorphism theorem** for groups: `(G / N) / (M / N) ≃* G / M`. -/
@[to_additive
      "**Noether's third isomorphism theorem** for additive groups: `(A / N) / (M / N) ≃+ A / M`."]
def quotientQuotientEquivQuotient : (G ⧸ N) ⧸ M.map (QuotientGroup.mk' N) ≃* G ⧸ M :=
  MonoidHom.toMulEquiv (quotientQuotientEquivQuotientAux N M h)
    (QuotientGroup.map _ _ (QuotientGroup.mk' N) (Subgroup.le_comap_map _ _))
    (by ext; simp)
    (by ext; 

Proof state:
case h.h
G : Type u
inst✝² : Group G
N : Subgroup G
nN : Subgroup.Normal N
H : Type v
inst✝¹ : Group H
M✝ : Type x
inst✝ : Monoid M✝
φ : G →* H
M : Subgroup G
nM : Subgroup.Normal M
h : N ≤ M
x✝ : G
⊢ (MonoidHom.comp
        (MonoidHom.comp (quotientQuotientEquivQuotientAux N M h)
          (map M (Subgroup.map (mk' N) M) (mk' N) (_ : M ≤ Subgroup.comap (mk' N) (Subgroup.map (mk' N) M))))
        (mk' M))
      x✝ =
    (MonoidHom.comp (MonoidHom.id (G ⧸ M)) (mk' M)) x✝

Next tactic:
simp
@[to_additive]
theorem subsingleton_quotient_top : Subsingleton (G ⧸ (⊤ : Subgroup G)) := by
  

Proof state:
G : Type u
inst✝² : Group G
N : Subgroup G
nN : Subgroup.Normal N
H : Type v
inst✝¹ : Group H
M : Type x
inst✝ : Monoid M
φ : G →* H
⊢ Subsingleton (G ⧸ ⊤)

Next tactic:
dsimp [HasQuotient.Quotient, QuotientGroup.instHasQuotientSubgroup, Quotient]
@[to_additive]
theorem subsingleton_quotient_top : Subsingleton (G ⧸ (⊤ : Subgroup G)) := by
  dsimp [HasQuotient.Quotient, QuotientGroup.instHasQuotientSubgroup, Quotient]
  

Proof state:
G : Type u
inst✝² : Group G
N : Subgroup G
nN : Subgroup.Normal N
H : Type v
inst✝¹ : Group H
M : Type x
inst✝ : Monoid M
φ : G →* H
⊢ Subsingleton (Quot Setoid.r)

Next tactic:
rw [leftRel_eq]
@[to_additive]
theorem subsingleton_quotient_top : Subsingleton (G ⧸ (⊤ : Subgroup G)) := by
  dsimp [HasQuotient.Quotient, QuotientGroup.instHasQuotientSubgroup, Quotient]
  rw [leftRel_eq]
  

Proof state:
G : Type u
inst✝² : Group G
N : Subgroup G
nN : Subgroup.Normal N
H : Type v
inst✝¹ : Group H
M : Type x
inst✝ : Monoid M
φ : G →* H
⊢ Subsingleton (Quot fun x y => x⁻¹ * y ∈ ⊤)

Next tactic:
exact Trunc.instSubsingletonTrunc