Zulip Chat Archive
Stream: maths
Topic: The proposition 1.4 of hungerford algebra textbook.
Lingwei Peng (彭灵伟) (Mar 27 2025 at 08:59):
This question comes from the Algebra book by Hungerford.
Let G be a semigroup. Then, G is a group if for all a, b \in G, the equations a \cdot x = b and y \cdot a = b have solutions in G.
This is the code in Lean 4. Can you help me to complete EquationGroup.exists_left_inv
?
import Mathlib
namespace MyAlgebra
universe u
class Magma (α : Type u) where
op : α → α → α
infixl:70 " * " => Magma.op
class Neutral (α : Type u) where
neutral : α
instance (priority := 300) Neutral.toOfNat1 {α} [Neutral α] : OfNat α (nat_lit 1) where
ofNat := ‹Neutral α›.neutral
instance (priority := 200) Neutral.ofOfNat1 {α} [OfNat α (nat_lit 1)] : Neutral α where
neutral := 1
class Inv (α : Type u) where
inv : α → α
postfix:max "⁻¹" => Inv.inv
class Semigroup (G : Type u) extends Magma G where
mul_assoc : ∀ a b c : G, a * b * c = a * (b * c)
class Monoid (G : Type u) extends Semigroup G, Neutral G where
one_mul : ∀ a : G, (1 : G) * a = a
mul_one : ∀ a : G, a * (1 : G) = a
class Group (G : Type u) extends Monoid G, Inv G where
inv_mul : ∀ a : G, a⁻¹ * a = 1
mul_inv : ∀ a : G, a * a⁻¹ = 1
class CommMagma (α : Type u) extends Magma α where
mul_comm : ∀ a b : α, a * b = b * a
class CommSemigroup (G : Type u) extends Semigroup G, CommMagma G where
class CommMonoid (G : Type u) extends Monoid G, CommSemigroup G
class CommGroup (G : Type u) extends Group G, CommSemigroup G
theorem Monoid.unique_left_neutral {G : Type u} [Monoid G] (e : G) (h : ∀ a : G, e * a = a) : e = 1 := by
rw [← h 1, mul_one]
theorem Monoid.unique_right_neutral {G : Type u} [Monoid G] (e : G) (h : ∀ a : G, a * e = a) : e = 1 := by
rw [← h 1, one_mul]
class LeftGroup (G : Type u) extends Semigroup G, Neutral G, Inv G where
one_mul : ∀ a : G, (1 : G) * a = a
inv_mul : ∀ a : G, a⁻¹ * a = 1
theorem LeftGroup.self_op_self_eq_one (G : Type u) [lg : LeftGroup G] (a : G) (h : a * a = a) : a = 1 := by
rw [← lg.one_mul a]
apply Eq.subst (motive := fun x => x * a = 1 ) (lg.inv_mul a)
rw [lg.mul_assoc, h]
exact lg.inv_mul a
theorem LeftGroup.mul_inv (G : Type u) [lg : LeftGroup G] (a : G) : a * a⁻¹ = 1 := by
apply lg.self_op_self_eq_one
rw [lg.mul_assoc]
apply Eq.subst (motive := fun (x : G) => a * x = a * a⁻¹) (lg.mul_assoc a⁻¹ a a⁻¹)
rw [lg.inv_mul, lg.one_mul]
theorem LeftGroup.mul_one (G : Type u) [lg : LeftGroup G] (a : G) : a * (1 : G) = a := by
rw [← lg.inv_mul a, ← lg.mul_assoc, lg.mul_inv, lg.one_mul]
instance LeftGroup.toGroup (G : Type u) [lg : LeftGroup G] : Group G where
one_mul := lg.one_mul
inv_mul := lg.inv_mul
mul_inv := lg.mul_inv
mul_one := lg.mul_one
theorem Group.unique_left_inv {G : Type u} [g : Group G] (a b : G) (h : a * b = 1) : a = b⁻¹ := by
apply Eq.subst (motive := fun x => a = x) (g.one_mul b⁻¹)
rw [← h, g.mul_assoc, g.mul_inv, g.mul_one]
theorem Group.unique_right_inv {G : Type u} [g : Group G] (a b : G) (h : b * a = 1) : a = b⁻¹ := by
apply Eq.subst (motive := fun x => a = x) (g.mul_one b⁻¹)
rw [← h, ← g.mul_assoc, g.inv_mul, g.one_mul]
theorem Group.inv_inv (G : Type u) [g : Group G] (a : G) : a⁻¹⁻¹ = a := by
apply Eq.symm
apply g.unique_right_inv
exact g.inv_mul a
theorem Group.inv_self_mul {G : Type u} [g : Group G] (a b : G) : a⁻¹ * (a * b) = b := by
rw [← g.mul_assoc, g.inv_mul, g.one_mul]
theorem Group.self_inv_mul {G : Type u} [g : Group G] (a b : G) : a * (a⁻¹ * b) = b := by
rw [← g.mul_assoc, g.mul_inv, g.one_mul]
theorem Group.mul_self_inv {G : Type u} [g : Group G] (a b : G) : a * b * b⁻¹ = a := by
rw [g.mul_assoc, g.mul_inv, g.mul_one]
theorem Group.mul_inv_self {G : Type u} [g : Group G] (a b : G) : a * b⁻¹ * b = a := by
rw [g.mul_assoc, g.inv_mul, g.mul_one]
theorem Group.inv_mul_inv {G : Type u} [g : Group G] (a b : G) : a⁻¹ * b⁻¹ = (b * a)⁻¹ := by
apply g.unique_left_inv
rw [g.mul_assoc, g.inv_self_mul, g.inv_mul]
theorem Group.cancel_left {G : Type u} [g : Group G] (a b c : G) (h : a * b = a * c) : b = c := by
rw [← g.inv_self_mul a b, h, g.inv_self_mul]
theorem Group.cancel_right {G : Type u} [g : Group G] (a b c : G) (h : b * a = c * a) : b = c := by
rw [← g.mul_self_inv b a, h, g.mul_self_inv]
theorem Group.ax_eq_b {G : Type u} [g : Group G] (a b x : G) (h : a * x = b) : x = a⁻¹ * b := by
apply g.cancel_left a
rw [g.self_inv_mul]
exact h
theorem Group.ya_eq_b {G : Type u} [g : Group G] (a b y : G) (h : y * a = b) : y = b * a⁻¹ := by
apply g.cancel_right a
rw [g.mul_inv_self]
exact h
class EquationGroup (G : Type u) extends Semigroup G where
left : ∀ a b : G, ∃ x : G, a * x = b
right : ∀ a b : G, ∃ x : G, x * a = b
nonempty : ∃ _ : G, True
theorem EquationGroup.exists_left_inv (G : Type u) [eg : EquationGroup G] : ∃ x : G, ∀ a, x * a = a := by
let some := Classical.choose eg.nonempty
have h := eg.right some some
let e := Classical.choose h
have h' := Classical.choose_spec h
apply Exists.intro e
intro a
end MyAlgebra
Lingwei Peng (彭灵伟) (Mar 27 2025 at 13:05):
The problem is solved, but the code could be optimized. Could you take a look and see if it can be improvemented?
import Mathlib
namespace MyAlgebra
universe u
class Magma (α : Type u) where
op : α → α → α
infixl:70 " * " => Magma.op
class Neutral (α : Type u) where
neutral : α
instance (priority := 300) Neutral.toOfNat1 {α} [Neutral α] : OfNat α (nat_lit 1) where
ofNat := ‹Neutral α›.neutral
instance (priority := 200) Neutral.ofOfNat1 {α} [OfNat α (nat_lit 1)] : Neutral α where
neutral := 1
class Inv (α : Type u) where
inv : α → α
postfix:max "⁻¹" => Inv.inv
class Semigroup (G : Type u) extends Magma G where
mul_assoc : ∀ a b c : G, a * b * c = a * (b * c)
class Monoid (G : Type u) extends Semigroup G, Neutral G where
one_mul : ∀ a : G, (1 : G) * a = a
mul_one : ∀ a : G, a * (1 : G) = a
class Group (G : Type u) extends Monoid G, Inv G where
inv_mul : ∀ a : G, a⁻¹ * a = 1
mul_inv : ∀ a : G, a * a⁻¹ = 1
class CommMagma (α : Type u) extends Magma α where
mul_comm : ∀ a b : α, a * b = b * a
class CommSemigroup (G : Type u) extends Semigroup G, CommMagma G where
class CommMonoid (G : Type u) extends Monoid G, CommSemigroup G
class CommGroup (G : Type u) extends Group G, CommSemigroup G
theorem Monoid.unique_left_neutral {G : Type u} [Monoid G] (e : G) (h : ∀ a : G, e * a = a) : e = 1 := by
rw [← h 1, mul_one]
theorem Monoid.unique_right_neutral {G : Type u} [Monoid G] (e : G) (h : ∀ a : G, a * e = a) : e = 1 := by
rw [← h 1, one_mul]
class LeftGroup (G : Type u) extends Semigroup G, Neutral G, Inv G where
one_mul : ∀ a : G, (1 : G) * a = a
inv_mul : ∀ a : G, a⁻¹ * a = 1
theorem LeftGroup.self_op_self_eq_one (G : Type u) [lg : LeftGroup G] (a : G) (h : a * a = a) : a = 1 := by
rw [← lg.one_mul a]
apply Eq.subst (motive := fun x => x * a = 1 ) (lg.inv_mul a)
rw [lg.mul_assoc, h]
exact lg.inv_mul a
theorem LeftGroup.mul_inv (G : Type u) [lg : LeftGroup G] (a : G) : a * a⁻¹ = 1 := by
apply lg.self_op_self_eq_one
rw [lg.mul_assoc]
apply Eq.subst (motive := fun (x : G) => a * x = a * a⁻¹) (lg.mul_assoc a⁻¹ a a⁻¹)
rw [lg.inv_mul, lg.one_mul]
theorem LeftGroup.mul_one (G : Type u) [lg : LeftGroup G] (a : G) : a * (1 : G) = a := by
rw [← lg.inv_mul a, ← lg.mul_assoc, lg.mul_inv, lg.one_mul]
instance LeftGroup.toGroup (G : Type u) [lg : LeftGroup G] : Group G where
one_mul := lg.one_mul
inv_mul := lg.inv_mul
mul_inv := lg.mul_inv
mul_one := lg.mul_one
theorem Group.unique_left_inv {G : Type u} [g : Group G] (a b : G) (h : a * b = 1) : a = b⁻¹ := by
apply Eq.subst (motive := fun x => a = x) (g.one_mul b⁻¹)
rw [← h, g.mul_assoc, g.mul_inv, g.mul_one]
theorem Group.unique_right_inv {G : Type u} [g : Group G] (a b : G) (h : b * a = 1) : a = b⁻¹ := by
apply Eq.subst (motive := fun x => a = x) (g.mul_one b⁻¹)
rw [← h, ← g.mul_assoc, g.inv_mul, g.one_mul]
theorem Group.inv_inv (G : Type u) [g : Group G] (a : G) : a⁻¹⁻¹ = a := by
apply Eq.symm
apply g.unique_right_inv
exact g.inv_mul a
theorem Group.inv_self_mul {G : Type u} [g : Group G] (a b : G) : a⁻¹ * (a * b) = b := by
rw [← g.mul_assoc, g.inv_mul, g.one_mul]
theorem Group.self_inv_mul {G : Type u} [g : Group G] (a b : G) : a * (a⁻¹ * b) = b := by
rw [← g.mul_assoc, g.mul_inv, g.one_mul]
theorem Group.mul_self_inv {G : Type u} [g : Group G] (a b : G) : a * b * b⁻¹ = a := by
rw [g.mul_assoc, g.mul_inv, g.mul_one]
theorem Group.mul_inv_self {G : Type u} [g : Group G] (a b : G) : a * b⁻¹ * b = a := by
rw [g.mul_assoc, g.inv_mul, g.mul_one]
theorem Group.inv_mul_inv {G : Type u} [g : Group G] (a b : G) : a⁻¹ * b⁻¹ = (b * a)⁻¹ := by
apply g.unique_left_inv
rw [g.mul_assoc, g.inv_self_mul, g.inv_mul]
theorem Group.cancel_left {G : Type u} [g : Group G] (a b c : G) (h : a * b = a * c) : b = c := by
rw [← g.inv_self_mul a b, h, g.inv_self_mul]
theorem Group.cancel_right {G : Type u} [g : Group G] (a b c : G) (h : b * a = c * a) : b = c := by
rw [← g.mul_self_inv b a, h, g.mul_self_inv]
theorem Group.ax_eq_b {G : Type u} [g : Group G] (a b x : G) (h : a * x = b) : x = a⁻¹ * b := by
apply g.cancel_left a
rw [g.self_inv_mul]
exact h
theorem Group.ya_eq_b {G : Type u} [g : Group G] (a b y : G) (h : y * a = b) : y = b * a⁻¹ := by
apply g.cancel_right a
rw [g.mul_inv_self]
exact h
class EquationGroup (G : Type u) extends Semigroup G where
left : ∀ a b : G, ∃ x : G, a * x = b
right : ∀ a b : G, ∃ x : G, x * a = b
nonempty : ∃ _ : G, True
theorem EquationGroup.exists_left_neutral{G : Type u} [eg : EquationGroup G] : ∃ x : G, ∀ a, x * a = a := by
let some := Classical.choose eg.nonempty
have h₁ := eg.right some some
let e := Classical.choose h₁
have he := Classical.choose_spec h₁
apply Exists.intro e
intro a
have h₃ := eg.left a a
let e' := Classical.choose h₃
have he' := Classical.choose_spec h₃
have h_some_inv := Classical.choose_spec (eg.left some e')
have h_a_inv := Classical.choose_spec (eg.right a e)
have h₇ : e * e' = e' := by
apply Eq.subst (motive := fun x => e * x = e') h_some_inv
rw [← eg.mul_assoc, he, h_some_inv]
have h₈ : e * e' = e := by
apply Eq.subst (motive := fun x => x * e' = e) h_a_inv
rw [eg.mul_assoc, he', h_a_inv]
have h₉ : e = e' := by
apply Eq.trans _ h₇
apply Eq.symm h₈
rw [h₉]
have h10 := eg.right a a
let e'' := Classical.choose h10
have he'' := Classical.choose_spec h10
have h11 := Classical.choose_spec (eg.right a e'')
have h12 : e'' * e' = e'' := by
apply Eq.subst (motive := fun x => x * e' = e'') h11
rw [eg.mul_assoc, he', h11]
have h13 := Classical.choose_spec (eg.left a e')
have h14 : e'' * e' = e' := by
apply Eq.subst (motive := fun x => e'' * x = e') h13
rw [← eg.mul_assoc, he'', h13]
have h15 : e' = e'' := by
apply Eq.trans _ h12
apply Eq.symm h14
rw [h15]
exact he''
noncomputable def EquationGroup.neutral{G : Type u} [eg : EquationGroup G] := Classical.choose (EquationGroup.exists_left_neutral (G := G))
theorem EquationGroup.one_mul{G : Type u} [eg : EquationGroup G] : ∀ a : G, EquationGroup.neutral * a = a := Classical.choose_spec (EquationGroup.exists_left_neutral (G := G))
noncomputable def EquationGroup.inv{G: Type u} [eg : EquationGroup G] := fun (a : G) => Classical.choose (eg.right a EquationGroup.neutral)
theorem EquationGroup.inv_mul{G : Type u} [eg : EquationGroup G] : ∀ a : G, (EquationGroup.inv a) * a = EquationGroup.neutral := by
intro a
simp [EquationGroup.inv]
apply Classical.choose_spec (eg.right a EquationGroup.neutral)
noncomputable instance EquationGroup.toLeftGroup (G : Type u) [eg : EquationGroup G] : LeftGroup G where
neutral := EquationGroup.neutral
inv := EquationGroup.inv
one_mul := EquationGroup.one_mul
inv_mul := EquationGroup.inv_mul
noncomputable instance EquationGroup.toGroup (G : Type u) [eg : EquationGroup G] : Group G :=
LeftGroup.toGroup (G := G)
end MyAlgebra
Yury G. Kudryashov (Mar 29 2025 at 03:39):
Why don't you reuse Mathlib's algebraic hierarchy?
Yury G. Kudryashov (Mar 29 2025 at 03:39):
Also, why have you decided to formalize this particular problem?
Lingwei Peng (彭灵伟) (Mar 29 2025 at 06:49):
I’m currently studying the group section in mathlib. I usually learn the source code by building a small code around it. Don’t laugh—I’ve been stuck on this problem for quite a while.
Yury G. Kudryashov (Mar 29 2025 at 16:05):
If you're looking for exercises, then you can
- reformulate the theorem in terms of Mathlib classes;
- prove this version and PR it to Mathlib.
Yury G. Kudryashov (Mar 29 2025 at 16:06):
BTW, is it enough to require that one of these divisions is possible?
Kevin Buzzard (Mar 29 2025 at 16:20):
I think that rolling your own algebra heirarchy can be a good exercise to learn something about the system, but ultimately it's kind of futile building on it because if you want to get anywhere then you need so many helper lemmas and domain-specific tactics that you may as well just use mathlib. A couple of comments on your code:
-- line 49
nth_rw 1 [← lg.inv_mul a]
--apply Eq.subst (motive := fun x => x * a = 1 ) (lg.inv_mul a)
I would never use Eq.subst directly; we have tactics which can do anything you want. Another example:
-- line 55
rw [← lg.mul_assoc a⁻¹]
--apply Eq.subst (motive := fun (x : G) => a * x = a * a⁻¹) (lg.mul_assoc a⁻¹ a a⁻¹)
Also, you don't need to use all this Classical.choose stuff when your goal is a prop: here is the first half of one of your theorems, with all the Classical stuff removed, and using calc
which is a far less painful way to do it than your continual have
's (I skip h7 and h8).
theorem EquationGroup.exists_left_neutral{G : Type u} [eg : EquationGroup G] : ∃ x : G, ∀ a, x * a = a := by
obtain ⟨some, _⟩ := eg.nonempty
obtain ⟨e, he⟩ := eg.right some some
use e
intro a
obtain ⟨e', he'⟩ := eg.left a a
obtain ⟨some_inv, h_some_inv⟩ := eg.left some e'
obtain ⟨a_inv, h_a_inv⟩ := eg.right a e
have h₉ : e = e' := calc
e = a_inv * a * e' := by rw [eg.mul_assoc, he', h_a_inv]
_ = e * e' := by rw [h_a_inv]
_ = e * (some * some_inv) := by rw [h_some_inv]
_ = e' := by rw [← eg.mul_assoc, he, h_some_inv]
rw [h₉]
...
I couldn't face doing any more but you get the point. If you look at the proofs in mathlib they are all much shorter.
Lingwei Peng (彭灵伟) (Mar 30 2025 at 08:31):
You are absolutely right. Using obtain (or Exists.elim) is more appropriate than Classical.choose. Thank you so much!
Last updated: May 02 2025 at 03:31 UTC