Zulip Chat Archive
Stream: maths
Topic: how to specify an identity for a semigroup ?
cairunze cairunze (Jun 16 2024 at 14:03):
I want to formalize this result in lean4, https://planetmath.org/acharacterizationofgroups
basically to show a certain semigroup is a group.
I think I have all the ingredients, but I cannot put them together in an instance.
The main difficulty for me is to produce an identity (instead of using an existing one) for the group, see near bottom part of the following code.
The problem seems to be that I can produce the wanted identity in tactic mode, but I don't know a way to put it in term mode.
thanks for the help~
import Mathlib.Tactic
variable {S : Type*} [Semigroup S]
namespace regsemigp
-- https://planetmath.org/acharacterizationofgroups
lemma idem_imp_left_id (i x: S) (h : ∀ (x : S), ∃! y, x * y * x = x) :
i * i = i → i * x = x := by
intro hi
rcases h (i * x) with ⟨ix',hix',hixu'⟩
rcases h ix' with ⟨ix'',hix'',hixu''⟩
-- ix = (ix)''
have h0 : i * x = ix'' := by
apply hixu''
apply hixu'
rw [← mul_assoc (i * x), ← mul_assoc (i * x),hix',hix']
-- i^2=i => ix=ix(ix)'ix=ix(ix)'iix => (ix)'i=(ix)'
have h1 : ix' * i = ix' := by
apply hixu'
rw [mul_assoc,← mul_assoc (ix' * i),mul_assoc ix',hi]
nth_rw 2 [← hix']
group
-- (ix)'=(ix)'(ix)''(ix)'=(ix)'(ix)(ix)'=((ix)'i)x(ix)'=(ix)'x(ix)'
have h2 : x = ix'' := by
apply hixu''
nth_rw 3 [← hix'']
rw [← h0,← mul_assoc,h1]
rw [h0,h2]
lemma idem_imp_right_id (i x: S) (h : ∀ (x : S), ∃! y, x * y * x = x) :
i * i = i → x * i = x := by
intro hi
rcases h (x * i) with ⟨xi',hxi',hxiu'⟩
rcases h xi' with ⟨xi'',hxi'',hxiu''⟩
-- ix = (ix)''
have h0 : x * i = xi'' := by
apply hxiu''
apply hxiu'
calc x * i * (xi' * (x * i) * xi') * (x * i) =
x * i * xi' * (x * i) * xi' * (x * i) := by group
_ = x * i := by rw [hxi',hxi']
-- i^2=i => xi=xi(xi)'xi=xii(xi)'xi => i(ix)'=(xi)'
have h1 : i * xi' = xi' := by
apply hxiu'
calc x * i * (i * xi') * (x * i) =
(x * (i * i) * xi') * (x * i) := by group
_ = x * i := by rw [hi,hxi']
-- (xi)'=(xi)'(xi)''(xi)'=(xi)'(xi)(xi)'=(xi)'x(i(xi)')=(xi)'x(xi)'
have h2 : x = xi'' := by
apply hxiu''
calc xi' * x * xi' = xi' * x * (i * xi') := by rw [h1]
_ = xi' * (x * i) * xi' := by group
_ = xi' * xi'' * xi' := by rw [h0]
_ = xi' := by rw [hxi'']
rw [h0,h2]
lemma exists_one {x : S} (h : ∀ (x : S), ∃! y, x * y * x = x) :
∃! (e : S), ∀ x, e * x = x ∧ x * e = x := by
rcases h x with ⟨x',hx',hxu'⟩
have idem : (x * x') * (x * x') = x * x' := by
calc x * x' * (x * x') = (x * x' * x) * x' := by group
_ = x * x' := by rw [hx']
use x * x'
constructor
intro y
exact ⟨idem_imp_left_id _ _ h idem,idem_imp_right_id _ _ h idem⟩
intro e he
rw [← idem_imp_left_id (x * x') e h idem,(he (x * x')).2]
lemma exists_inv {x e: S} (h : ∀ (x : S), ∃! y, x * y * x = x)
(h1 : ∀ x, e * x = x ∧ x * e = x) :
∃ (y : S), x * y = e ∧ y * x = e := by
rcases h x with ⟨x',hx',hxu'⟩
use x'
have ideml : (x * x') * (x * x') = x * x' := by rw [← mul_assoc,hx']
have idemr : (x' * x) * (x' * x) = x' * x := by
rw [mul_assoc x',← mul_assoc x,hx']
constructor
· rw [← idem_imp_left_id (x * x') e h ideml, (h1 (x * x')).2]
· rw [← idem_imp_right_id (x' * x) e h idemr,(h1 (x' * x)).1]
instance (h0 : Nonempty S) -- not sure this is the correct way to specify nonemptiness
(h : ∀ (x : S), ∃! y, x * y * x = x) : Group S where
mul := (· * ·)
mul_assoc := mul_assoc
one := sorry -- don't know how proceed here
one_mul := by
cases h0 with -- this will obtain an element in S, but looks unnatural to me
| _ x =>
rcases h x with ⟨x',hx',hxu'⟩
have ideml : (x * x') * (x * x') = x * x' := by rw [← mul_assoc,hx']
intro y
apply idem_imp_left_id _ _ h
-- ⊢ 1 * 1 = 1
sorry
mul_one := sorry
inv := sorry
mul_left_inv := sorry
end regsemigp
Edward van de Meent (Jun 16 2024 at 19:23):
Since you're choosing the identity by making use of a term from an exists-statement, you will need some sort of axiom of choice, which in this case will most likely take the form of docs#Exists.choose
Edward van de Meent (Jun 16 2024 at 19:26):
I'm not sure that this will make for great defEq though. I think that this at most should be a def, or maybe should be stated in a reduced form, stating that a unit and inverse exist rather than giving the terms.
cairunze cairunze (Jun 17 2024 at 04:58):
Edward van de Meent said:
Since you're choosing the identity by making use of a term from an exists-statement, you will need some sort of axiom of choice, which in this case will most likely take the form of docs#Exists.choose
Ah this is helpful, I did not realize that I have to use both Classical.choice
and Classical.choose
(maybe?). So the definition checks out, and I can provide a candidate for the identity. The instance (or I defined elsewhere) has to be made noncomputable.
Now, however, in the subsequent parts, Lean does not recognize the identity
I defined is the same as 1
. Any way to salvage this? Thanks.
noncomputable instance (h0 : Nonempty S)
(h : ∀ (x : S), ∃! y, x * y * x = x) : Group S where
mul := (· * ·)
mul_assoc := mul_assoc
one :=
let x : S := Classical.choice h0
let y : S := Classical.choose (h x)
x * y
one_mul := by
let x : S := Classical.choice h0
rcases h x with ⟨x',hx',hxu'⟩
have ideml : (x * x') * (x * x') = x * x' := by rw [← mul_assoc,hx']
intro y
apply idem_imp_left_id _ _ h
-- ⊢ 1 * 1 = 1 <-- this `1` seems unrelated to the `one` prescribed above
sorry
mul_one := sorry
inv := sorry
mul_left_inv := sorry
cairunze cairunze (Jun 17 2024 at 07:12):
It turns out that the 1
and the one
are indeed not unrelated. I hover the mouse over the 1
in the tactic state and get that it follows the definition. So I made some changes to the ingredients.
lemma exists_one (h0 : Nonempty S) (h : ∀ (x : S), ∃! y, x * y * x = x) :
∃! (e : S), ∀ x, e * x = x ∧ x * e = x := by
let x : S := Classical.choice h0
rcases h x with ⟨x',hx',hxu'⟩
have idem : (x * x') * (x * x') = x * x' := by
calc x * x' * (x * x') = (x * x' * x) * x' := by group
_ = x * x' := by rw [hx']
use x * x'
constructor
intro y
exact ⟨idem_imp_left_id _ _ h idem,idem_imp_right_id _ _ h idem⟩
intro e he
rw [← idem_imp_left_id (x * x') e h idem,(he (x * x')).2]
noncomputable example (h0 : Nonempty S)
(h : ∀ (x : S), ∃! y, x * y * x = x) : Group S where
mul := (· * ·)
mul_assoc := mul_assoc
one := Classical.choose (exists_one h0 h)
one_mul := λ y ↦ ((Classical.choose_spec (exists_one h0 h)).1 y).1
mul_one := λ y ↦ ((Classical.choose_spec (exists_one h0 h)).1 y).2
inv := sorry
mul_left_inv := sorry
So far everything compiles and at least the monoid part is done, only a bit ugly though.
Maybe there's a better way to this?
cairunze cairunze (Jun 17 2024 at 16:04):
I think finally the following (with other parts above together) works.
The final part on the inverse is creating similar problem as before of not seemingly to have the 1
in the goal showing anything obvious related to the rest. I have to modify the identity 1
in the lemma to resolve this nesting.
The overall Classical.choose
thing is making the code less readable, I hope there's a better way to present this.
(I realized that there are redundancies in the lemmas, for example, the uniqueness of identity is not needed, and so on.)
lemma exists_inv'' (h0 : Nonempty S) (h : ∀ (x : S), ∃! y, x * y * x = x)
: ∀ (x : S), ∃ y, y * x = Classical.choose (exists_one h0 h) := by
intro x
rcases h x with ⟨x',hx',hxu'⟩
use x'
have h1 :=(Classical.choose_spec (exists_one h0 h)).1
have idemr : (x' * x) * (x' * x) = x' * x := by
rw [mul_assoc x',← mul_assoc x,hx']
rw [← idem_imp_right_id (x' * x) (Classical.choose (exists_one h0 h)) h idemr,(h1 (x' * x)).1]
noncomputable example (h0 : Nonempty S)
(h : ∀ (x : S), ∃! y, x * y * x = x) : Group S where
mul := (· * ·)
mul_assoc := mul_assoc
one := Classical.choose (exists_one h0 h)
one_mul := λ y ↦ ((Classical.choose_spec (exists_one h0 h)).1 y).1
mul_one := λ y ↦ ((Classical.choose_spec (exists_one h0 h)).1 y).2
inv := λ x ↦ Classical.choose (exists_inv'' h0 h x)
mul_left_inv := λ x ↦ Classical.choose_spec (exists_inv'' h0 h x)
Edward van de Meent (Jun 17 2024 at 21:46):
one approach is to use h
to define a function f : S -> S
with the property that x * f x * x = x
and x * y * x = x -> y = f x
using AoC, and (where necessary) assume Inhabited S
rather than Nonempty S
so you (constructively) have access to default : S
as a generic element of S
. If you do this, you will be able to construct all of the rest of the argument without AoC, and because you're proving things about constructions using this f
rather than Exists.Choose
for a specific lemma, it will look nice too. the only question then is "what is a nice name for this function f
that carries its intuition?"
cairunze cairunze (Jun 18 2024 at 03:06):
Edward van de Meent said:
one approach is to use
h
to define a functionf : S -> S
with the property thatx * f x * x = x
andx * y * x = x -> y = f x
using AoC, and (where necessary) assumeInhabited S
rather thanNonempty S
so you (constructively) have access todefault : S
as a generic element ofS
. If you do this, you will be able to construct all of the rest of the argument without AoC, and because you're proving things about constructions using thisf
rather thanExists.Choose
for a specific lemma, it will look nice too. the only question then is "what is a nice name for this functionf
that carries its intuition?"
Wow, this is a nice way to extract the element, by semigroup theory jargon, probably f
should be called weak inverse
or something, cf, https://en.wikipedia.org/wiki/Weak_inverse
However, I cannot work it out in the proof, since it only provide the element but not its properties (maybe need to write it in another lemma?). So instead, I just defined the identity and inverse, along with some lemmas about their property.
So the final bundled instance seems a little bit cleaner...
-- noncomputable def weak_inv [Inhabited S]
-- (h : ∀ (x : S), ∃! y, x * y * x = x) : S → S :=
-- λ x ↦ Classical.choose (h x)
lemma exists_one [Inhabited S] (h : ∀ (x : S), ∃! y, x * y * x = x) :
∃ (e : S), ∀ x, e * x = x ∧ x * e = x := by
let x : S := (default : S)
-- let x' : S := weak_inv h x
rcases h x with ⟨x',hx',hxu'⟩
have idem : (x * x') * (x * x') = x * x' := by
calc x * x' * (x * x') = (x * x' * x) * x' := by group
_ = x * x' := by rw [hx']
use x * x'
intro y
exact ⟨idem_imp_left_id _ _ h idem,idem_imp_right_id _ _ h idem⟩
noncomputable def one_S [Inhabited S]
(h : ∀ (x : S), ∃! y, x * y * x = x) : S
:= Classical.choose (exists_one h)
lemma exists_inv [Inhabited S]
(h : ∀ (x : S), ∃! y, x * y * x = x)
: ∀ (x : S), ∃ y, y * x = one_S h := by
intro x
rcases h x with ⟨x',hx',hxu'⟩
use x' -- = weak_inv h x
have h1 := Classical.choose_spec (exists_one h)
have idemr : (x' * x) * (x' * x) = x' * x := by
rw [mul_assoc x',← mul_assoc x,hx']
rw [← idem_imp_right_id (x' * x) (one_S h) h idemr,one_S,(h1 (x' * x)).1]
noncomputable def inv_S [Inhabited S]
(h : ∀ (x : S), ∃! y, x * y * x = x) : S → S
:= λ x ↦ Classical.choose (exists_inv h x)
lemma one_S_left_spec [Inhabited S]
(h : ∀ (x : S), ∃! y, x * y * x = x)
: ∀ x, (one_S h) * x = x
:= λ x ↦ (Classical.choose_spec (exists_one h) x).1
lemma one_S_right_spec [Inhabited S]
(h : ∀ (x : S), ∃! y, x * y * x = x)
: ∀ x, x * (one_S h) = x
:= λ x ↦ (Classical.choose_spec (exists_one h) x).2
lemma inv_S_spec [Inhabited S]
(h : ∀ (x : S), ∃! y, x * y * x = x)
: ∀ x, (inv_S h x) * x = one_S h
:= λ x ↦ Classical.choose_spec (exists_inv h x)
noncomputable instance [Inhabited S]
(h : ∀ (x : S), ∃! y, x * y * x = x) : Group S where
mul := (· * ·)
mul_assoc := mul_assoc
one := one_S h
one_mul := one_S_left_spec h
mul_one := one_S_right_spec h
inv := λ x ↦ inv_S h x
mul_left_inv := inv_S_spec h
Edward van de Meent (Jun 18 2024 at 07:34):
As a small note, you don't need to specify mul
or mul_assoc
, those can be filled automatically since you're assuming Semigroup S
Edward van de Meent (Jun 18 2024 at 07:46):
here is how to get the properties for such a definition:
variable {S:Type*} [Semigroup S]
noncomputable def weak_inv (h : ∀ (x : S), ∃! y, x * y * x = x) : S → S :=
λ x ↦ (h x).exists.choose
lemma weak_inv_prop (h : ∀ (x : S), ∃! y, x * y * x = x) :
∀ x, x * weak_inv h x * x = x := by
intro x
exact (h x).exists.choose_spec
lemma weak_inv_unique (h : ∀ (x : S), ∃! y, x * y * x = x) :
∀ y x, x * y * x = x → y = weak_inv h x := by
intro y x hy
exact (h x).unique hy (weak_inv_prop h x)
cairunze cairunze (Jun 23 2024 at 10:22):
Edward van de Meent said:
here is how to get the properties for such a definition:
variable {S:Type*} [Semigroup S] noncomputable def weak_inv (h : ∀ (x : S), ∃! y, x * y * x = x) : S → S := λ x ↦ (h x).exists.choose lemma weak_inv_prop (h : ∀ (x : S), ∃! y, x * y * x = x) : ∀ x, x * weak_inv h x * x = x := by intro x exact (h x).exists.choose_spec lemma weak_inv_unique (h : ∀ (x : S), ∃! y, x * y * x = x) : ∀ y x, x * y * x = x → y = weak_inv h x := by intro y x hy exact (h x).unique hy (weak_inv_prop h x)
This seems more civilized! Thanks a lot for the various suggestions!
I get to get the rid of a lot of the rcases
.
I think for better presentation, I need to write some small lemmas tagged with @[simp], and then see what happens.
example (i x: S) : i * i = i → i * x = x := by
intro hi
set ix' := weak_inv h (i * x) with hix'
set ix'' := weak_inv h ix' with hix''
-- ix = (ix)''
have h0 : i * x = ix'' := by
apply weak_inv_unique
apply weak_inv_unique
rw [← mul_assoc (i * x), ← mul_assoc (i * x),weak_inv_prop,weak_inv_prop]
-- i^2=i => ix=ix(ix)'ix=ix(ix)'iix => (ix)'i=(ix)'
have h1 : ix' * i = ix' := by
apply weak_inv_unique
rw [mul_assoc,← mul_assoc (ix' * i),mul_assoc ix',hi,mul_assoc ix',← mul_assoc (i*x)]
apply weak_inv_prop h (i * x)
-- (ix)'=(ix)'(ix)''(ix)'=(ix)'(ix)(ix)'=((ix)'i)x(ix)'=(ix)'x(ix)'
have h2 : x = ix'' := by
apply weak_inv_unique
nth_rw 3 [← weak_inv_prop h ix']
rw [← hix'',← h0,← mul_assoc,h1]
rw [h0,h2]
lemma exists_one : ∃ (e : S), ∀ x, e * x = x ∧ x * e = x := by
let x : S := (default : S)
let x' := weak_inv h x
have idem : (x * x') * (x * x') = x * x' := by
calc x * x' * (x * x') = (x * x' * x) * x' := by group
_ = x * x' := by rw [weak_inv_prop]
use x * x'
intro y
exact ⟨idem_imp_left_id h _ _ idem,idem_imp_right_id h _ _ idem⟩
lemma exists_inv : ∀ (x : S), ∃ y, y * x = one_S h := by
intro x
let x' := weak_inv h x
use x'
have h1 := Classical.choose_spec (exists_one h)
have idemr : (x' * x) * (x' * x) = x' * x := by
rw [mul_assoc x',← mul_assoc x,weak_inv_prop]
rw [← idem_imp_right_id h (x' * x) (one_S h) idemr,one_S,(h1 (x' * x)).1]
Last updated: May 02 2025 at 03:31 UTC