Zulip Chat Archive

Stream: mathlib4

Topic: Define Quotient Group


Nick_adfor (Oct 19 2025 at 16:19):

I'm now trying to define quotient group in this way. But I'm not familiar with Classical.choose. As in the sorry I need to prove Classical.choose ⋯ = g.

import Mathlib

suppress_compilation

variable {G : Type} [Group G] (H : Subgroup G) [H.Normal]

open Pointwise

structure QGroup : Type where
  carrier : Set G
  isCoset :  g : G, carrier = g  H

namespace QGroup

variable {H}

instance : SetLike (QGroup H) G where
  coe C := C.carrier
  coe_injective' := by
    intro C D; cases C; cases D; simp

@[ext]
lemma ext {C D : QGroup H} (h : (C : Set G) = D) : C = D := by
  cases C; cases D; simp at h; simp [h]

def out (C : QGroup H) : G := Classical.choose C.isCoset

@[simp]
lemma out_spec (C : QGroup H) : C.out  H = (C : Set G) :=
  Classical.choose_spec C.isCoset |>.symm

lemma mem_iff_out (C : QGroup H) (g : G) : g  C   h  H, g = C.out  h := by
  rw [ SetLike.mem_coe,  C.out_spec, Set.mem_smul_set]
  tauto

variable (H) in
def gen (g : G) : QGroup H :=
  g  H, g, rfl⟩⟩

lemma gen_def (g : G) : (gen H g : Set G) = g  H := rfl

@[simp]
lemma mem_gen_iff (g : G) {x : G} : x  gen H g   h  H, x = g * h := by
  rw [ SetLike.mem_coe, gen_def, Set.mem_smul_set]
  tauto

@[simp]
lemma gen_out (C : QGroup H) : gen H C.out = C := by
  ext g
  simp only [SetLike.mem_coe, mem_gen_iff]
  rw [C.mem_iff_out]
  rfl

@[simp]
lemma mem_out_gen (g : G) {x : G} : x  ((gen H g).out  H : Set G)  x  (g  H : Set G) := by
  simp [Set.mem_smul_set, eq_comm]


@[elab_as_elim]
theorem gen_induction {P : QGroup H  Prop}
    (h :  g : G, P (gen H g)) :
     C : QGroup H, P C := by
  intro C
  rw [ C.gen_out]
  tauto

@[simp]
theorem gen_eq_iff (g : G) (C : QGroup H) : gen H g = C  g  C := by
  constructor
  · rintro rfl
    simp
  · intro h
    rw [C.mem_iff_out] at h
    obtain x, hx, rfl := h
    ext y
    simp only [smul_eq_mul, SetLike.mem_coe, mem_gen_iff]
    constructor
    · rintro y, hy, rfl
      rw [C.mem_iff_out]
      use x * y, mul_mem hx hy
      simp [mul_assoc]
    · rw [C.mem_iff_out]
      rintro y, hy, rfl
      use x⁻¹ * y, mul_mem (H.inv_mem hx) hy
      simp [mul_assoc]

instance : One (QGroup H) where
  one := H, 1, by simp⟩⟩

lemma one_def : ((1 : QGroup H) : Set G) = H := rfl

@[simp]
lemma mem_one_iff {g : G} : g  (1 : QGroup H)  g  H := Iff.rfl

@[simp]
lemma gen_one : gen H 1 = 1 := by
  ext g
  simp

instance : Mul (QGroup H) where
  mul C D := C.out  D.out  H, C.out * D.out, by simp [mul_smul, out_spec]⟩⟩

lemma mul_def (C D : QGroup H) :
    ((C * D : QGroup H) : Set G) = C.out  D.out  H := rfl

Aaron Liu (Oct 19 2025 at 16:23):

everything you can know about Classical.choose is contained in Classical.choose_spec

Aaron Liu (Oct 19 2025 at 16:24):

when working with quotients like this I strongly discourage the use of QGroup.out

Nick_adfor (Oct 19 2025 at 16:25):

What will QGroup.out cause?

Aaron Liu (Oct 19 2025 at 16:26):

the preferred way to do quotients if you don't have a way to pick out a canonical representative is to use docs#Quotient instead of making it the equivalence classes

Aaron Liu (Oct 19 2025 at 16:26):

that way you have access to docs#Quotient.lift

Nick_adfor (Oct 19 2025 at 16:28):

Now the problem is truly (gen H g).out = g, but I cannot Choose one.

Aaron Liu (Oct 19 2025 at 16:29):

Nick_adfor said:

Now the problem is truly (gen H g).out = g, but I cannot Choose one.

but that's not always true

Nick_adfor (Oct 19 2025 at 16:38):

It should be (gen H g).out ∈ (gen H g : Set G)

Nick_adfor (Oct 19 2025 at 16:59):

@[simp]
lemma gen_mul_gen (g g' : G) : gen H g * gen H g' = gen H (g * g') := by
  ext x
  simp only [SetLike.mem_coe, mul_def, gen_def, Set.mem_smul_set]
  constructor
  · rintro w, hw, rfl
    obtain h₂, hh₂, rfl := hw
    have mem1 : (gen H g).out  (gen H g).out  (H : Set G) := by
      use 1, H.one_mem
      simp
    rw [mem_out_gen] at mem1
    rw [Set.mem_smul_set] at mem1
    obtain h₁, hh₁, h_eq1 := mem1
    have mem2 : (gen H g').out  (gen H g').out  (H : Set G) := by
      use 1, H.one_mem
      simp
    rw [mem_out_gen] at mem2
    rw [Set.mem_smul_set] at mem2
    obtain k, hk, h_eq2 := mem2
    rw [<-h_eq1, <-h_eq2]
    use (g'⁻¹ * h₁ * g') * (k * h₂)
    constructor
    · have hh₁' : h₁  H := hh₁
      have hk' : k  H := hk
      have conj_mem : g'⁻¹ * h₁ * g'  H := by exact?
      have mul_mem1 : k * h₂  H := by exact (Subgroup.mul_mem_cancel_right H hh₂).mpr hk
      exact mul_mem conj_mem mul_mem1
    · simp [mul_assoc]

It is the second exact? giving the wrong proof I've ever seen today......

Notification Bot (Oct 19 2025 at 17:18):

3 messages were moved from this topic to #mathlib4 > exact? gives incorrect line-wrapping by Eric Wieser.

Nick_adfor (Oct 20 2025 at 06:24):

It is really a disaster to Choose. I really cannot understand how the definition Choose gH. It is not the same as maths.

@[simp]
lemma gen_mul_gen (g g' : G) : gen H g * gen H g' = gen H (g * g') := by
  ext x
  simp only [SetLike.mem_coe, mem_gen_iff]
  constructor
  · rintro w, hw, rfl
    obtain h₂, hh₂, rfl := hw
    have mem1 : (gen H g).out  (gen H g).out  (H : Set G) := by
      use 1, H.one_mem
      simp
    rw [mem_out_gen] at mem1
    obtain h₁, hh₁, h_eq1 := mem1
    have mem2 : (gen H g').out  (gen H g').out  (H : Set G) := by
      use 1, H.one_mem
      simp
    rw [mem_out_gen] at mem2
    obtain k, hk, h_eq2 := mem2
    rw [<-h_eq1, <-h_eq2]
    use (g'⁻¹ * h₁ * g') * (k * h₂)
    constructor
    · have hh₁' : h₁  H := hh₁
      have hk' : k  H := hk
      have conj_mem : g'⁻¹ * h₁ * g'  H := by
        (expose_names; exact Subgroup.Normal.conj_mem' inst_1 h₁ hh₁ g')
      have mul_mem1 : k * h₂  H := by
        exact (Subgroup.mul_mem_cancel_right H hh₂).mpr hk
      exact mul_mem conj_mem mul_mem1
    · simp only [smul_eq_mul, mul_assoc, mul_inv_cancel_left]

  · rintro h, hh, rfl
    have : g' * h  (gen H g').out  (H : Set G) := by
      rw [(gen H g').out_spec]
      exact h, hh, rfl
    rw [mem_out_gen] at this
    obtain k, hk, h_eq := this
    have h1 : (gen H g).out  g  (H : Set G) := by
      rw [ gen_def,  (gen H g).out_spec]
      exact 1, H.one_mem, by simp
    have h2 : (gen H g').out  g'  (H : Set G) := by
      rw [ gen_def,  (gen H g').out_spec]
      exact 1, H.one_mem, by simp
    rcases h1 with a, ha, h1_eq
    rcases h2 with b, hb, h2_eq
    let w := (gen H g').out * (a⁻¹ * b⁻¹ * h)
    have hw : w  (gen H g').out  (H : Set G) := by
      rw [Set.mem_smul_set]
      exact a⁻¹ * b⁻¹ * h, mul_mem (mul_mem (inv_mem ha) (inv_mem hb)) hh, rfl
    refine (gen H g').out * (a⁻¹ * b⁻¹ * h), a⁻¹ * b⁻¹ * h, mul_mem (mul_mem (inv_mem ha) (inv_mem hb)) hh, rfl, ?_⟩
    simp
    have h1_simple : (gen H g).out = g * a := Eq.symm h1_eq
    have h2_simple : (gen H g').out = g' * b := Eq.symm h2_eq
    rw [h1_simple, h2_simple]
    norm_num

    have mem1 : (gen H g).out  (gen H g).out  (H : Set G) := by
      use 1, H.one_mem
      simp
    rw [mem_out_gen] at mem1
    obtain h₁, hh₁, h_eq1 := mem1
    have mem2 : (gen H g').out  (gen H g').out  (H : Set G) := by
      use 1, H.one_mem
      simp
    rw [mem_out_gen] at mem2
    obtain k, hk, h_eq2 := mem2

    have h_conj : g'⁻¹ * h₁ * g'  H := by
      (expose_names; exact Subgroup.Normal.conj_mem' inst_1 h₁ hh₁ g')
    have prodH : (g'⁻¹ * h₁ * g' * k)  H := by
      exact (Subgroup.mul_mem_cancel_right H hk).mpr h_conj
    sorry

Patrick Massot (Oct 20 2025 at 07:05):

Nick_adfor said:

It is really a disaster to Choose. I really cannot understand how the definition Choose gH. It is not the same as maths.

Aaron already told you, you will keep suffering until you accept to do the same thing as on paper (except in super elementary courses): forget about equivalence classes as subset of the original group and embrace the universal property of quotients.

Kevin Buzzard (Oct 20 2025 at 09:32):

Nick_adfor said:

It is the second exact? giving the wrong proof I've ever seen today......

Sure, but exact? is telling you the relevant lemma, it's just struggling to apply it because Subgroup.Normal.conj_mem' takes a proof that a subgroup is normal as an explicit input, whereas Subgroup.Normal is a class. This is usually the reason that exact? spits out weird stuff about exposing names. have conj_mem : g'⁻¹ * h₁ * g' ∈ H := Subgroup.Normal.conj_mem' inferInstance _ hh₁' _ works fine.

Eric Wieser (Oct 20 2025 at 09:51):

Kevin, see the linked thread I moved to; the complaint is that "Try this" uses incorrect indentation.

Nick_adfor (Oct 20 2025 at 10:03):

Patrick Massot said:

Nick_adfor said:

It is really a disaster to Choose. I really cannot understand how the definition Choose gH. It is not the same as maths.

Aaron already told you, you will keep suffering until you accept to do the same thing as on paper (except in super elementary courses): forget about equivalence classes as subset of the original group and embrace the universal property of quotients.

It should be:

Forward direction (⇒)

Assume x ∈ (gH)(g'H). Then ∃ h₁, h₂ ∈ H such that
x = (g h₁)(g' h₂) = g h₁ g' h₂.

Since H is normal, h₁ g' = g' h₃ where h₃ = g'⁻¹ h₁ g' ∈ H.
Thus:
x = g (g' h₃) h₂ = g g' (h₃ h₂).
Let h = h₃ h₂ ∈ H, then x = g g' h.

Reverse direction (⇐)

Assume x = g g' h with h ∈ H.
Take h₁ = 1 ∈ H, h₂ = h ∈ H, then:
x = (g · 1) · (g' · h) ∈ (gH)(g'H).

Kevin Buzzard (Oct 20 2025 at 14:10):

Yes but what people are trying to tell you is that your definition of a quotient group is not idiomatic Lean. The reason Lean has a Quotient construction is precisely so you don't have to be in this hell. However I am sure that you can plough your way through the hell if you like; indeed I tried doing this myself many years ago as an experiment and I did make it through. One big difference is that with Quotient so many more things are rfl whereas everything is noncomputable with the Set approach.

Kevin Buzzard (Oct 20 2025 at 14:35):

Eric Wieser said:

Kevin, see the linked thread I moved to; the complaint is that "Try this" uses incorrect indentation.

Right: there are I think two independent issues here -- one is that the proof which exact? gives is weird (because it needs a name for a typeclass) and the other is that it doesn't compile (because of indentation issues).


Last updated: Dec 20 2025 at 21:32 UTC