Zulip Chat Archive
Stream: new members
Topic: direct product of normal disjoint subgroups mulEquiv to join
Alex Brodbelt (Feb 22 2025 at 23:19):
Hi,
I have thought about this for a while and gradually I am able to state more and more of this result in lean, but I suspect there is some roadblock for why it cannot be done?
Otherwise, surely such a theorem should be/is(???) in mathlib?
My idea is to use docs#mul_normal and maybe make it noncomputable as I need to choose and
(I believe these are the exact assumptions that are necessary - but it is late so I could be wrong ...Anyway, the assumptions are at least a subset of the assumptions below)
import Mathlib
open Subgroup
def prod_iso_join_of_disjoint_of_normal {G : Type*} [Group G] (H K : Subgroup G)
(hHK : H ⊓ K = ⊥) [hH : Normal H] [hK : Normal K] : H × K ≃* (H ⊔ K :) where
toFun := fun h_k => ⟨h_k.1 * h_k.2, mul_mem_sup h_k.1.property h_k.2.property⟩
invFun := fun h_k => sorry
-- How can I use Subgroup.mul_normal to extract h ∈ H and k ∈ K? Ideally the proofs then don't become horrendous... I don't have high hopes.
-- rewrites in term mode are hard...
left_inv := sorry
right_inv := sorry
map_mul' := sorry
This might be a silly question, but I suspect other undergrads will be asking themselves this as well if this has not been asked already.
Aaron Liu (Feb 23 2025 at 00:41):
This requires an algorithm to "factor" an element of H ⊔ K
into an element of H
and an element of G
. As stated this can't be computable, because such an algorithm does not always exist.
Kevin Buzzard (Feb 23 2025 at 09:26):
I would first define the group hom, then prove that it's bijective, and then make the noncomputable iso using docs#MulEquiv.ofBijective . The proofs shouldn't be horrendous, they should be short and quite nice!
Kevin Buzzard (Feb 23 2025 at 09:27):
It's not unimaginable that it's not there, because you're jumping between subgroups and groups, which are unfortunately different things in type theory. People often prefer to stick with one or the other.
Kevin Buzzard (Feb 23 2025 at 09:32):
PS disjoint
should only be in the name of a declaration if docs#Disjoint is used in the statement somewhere, and iso
should only be there if docs#CategoryTheory.Iso is present. Check out #naming to learn more.
Alex Brodbelt (Feb 23 2025 at 11:07):
Ah of course - and I suppose it is better if I call it MulEquiv then?
Kevin Buzzard (Feb 23 2025 at 13:46):
Alex Brodbelt said:
Ah of course - and I suppose it is better if I call it MulEquiv then?
mulEquiv
but yes!
Alex Brodbelt (Feb 27 2025 at 15:31):
Forgot to come back and post the formalization in case it is useful for someone else...
import Mathlib
open Subgroup
def prod_monoidHom_join {G : Type*} [Group G] (H K : Subgroup G) [hH : Normal H] [hK : Normal K]
(hHK : Disjoint H K) : H × K →* (H ⊔ K :) where
toFun h_k := ⟨h_k.1 * h_k.2, mul_mem_sup h_k.1.property h_k.2.property⟩
map_one' := by simp
map_mul' := by
rintro ⟨⟨h₁, hh₁⟩, ⟨k₁, hk₁⟩⟩ ⟨⟨h₂, hh₂⟩, ⟨k₂, hk₂⟩⟩
simp
rw [mul_assoc, mul_assoc, ← mul_assoc k₁,
(Commute.eq (commute_of_normal_of_disjoint K H hK hH (Disjoint.symm hHK) k₁ h₂ hk₁ hh₂))]
group
open Function
lemma Bijective_prod_monoidHom_join {G : Type*} [Group G] (H K : Subgroup G) [hH : Normal H]
[hK : Normal K] (hHK : Disjoint H K) : Bijective (prod_monoidHom_join H K hHK) := by
refine ⟨?injective, ?surjective⟩
case injective =>
rintro ⟨⟨h₁, h₁_in_H⟩, k₁, k₁_in_K⟩ ⟨⟨h₂, h₂_in_H⟩, k₂, k₂_in_K⟩ h
simp [prod_monoidHom_join] at h
have : h₁⁻¹ * h₂ * k₂ * k₁⁻¹ = 1 := by
rw [mul_assoc, mul_assoc, ← mul_assoc h₂, ← h]
group
-- show h₁ * h₂⁻¹ = 1 and k₁ * k₂⁻¹ = 1
have H₁ : k₂ * k₁⁻¹ = (k₁ * k₂⁻¹)⁻¹ := by
group
have key₁ : h₁⁻¹ * h₂ = k₁ * k₂⁻¹ := by
rw [mul_assoc] at this
rw [H₁, mul_inv_eq_one] at this
exact this
have mul_in_H : k₁ * k₂⁻¹ ∈ H := key₁.symm ▸ mul_mem (inv_mem h₁_in_H) h₂_in_H
have mul_in_K : k₁ * k₂⁻¹ ∈ K := mul_mem k₁_in_K (inv_mem k₂_in_K)
rw [disjoint_iff_inf_le] at hHK
have key₂ : k₁ * k₂⁻¹ = 1 := by
rw [← mem_bot]
apply hHK
refine mem_inf.mpr ⟨mul_in_H, mul_in_K⟩
rw [key₂] at key₁
rw [inv_mul_eq_one] at key₁
rw [mul_inv_eq_one] at key₂
ext <;> simp [key₁, key₂]
case surjective =>
rintro ⟨x, hx⟩
rw [← SetLike.mem_coe, mul_normal] at hx
obtain ⟨h, h_in_H, k, k_in_K, hh⟩ := hx
use ⟨⟨h, h_in_H⟩, ⟨k, k_in_K⟩⟩
simp [prod_monoidHom_join, hh]
noncomputable def prod_mulEquiv_join_of_normal {G : Type*} [Group G] (H K : Subgroup G)
(hHK : Disjoint H K) [hH : Normal H] [hK : Normal K] : H × K ≃* (H ⊔ K :) :=
MulEquiv.ofBijective (prod_monoidHom_join H K hHK) (Bijective_prod_monoidHom_join H K hHK)
Kevin Buzzard (Feb 27 2025 at 18:32):
Nice!
I feel like it's golfable but I couldn't immediately see how to make it much shorter. You should probably get out of the habit of using non-terminal simp
s though.
Eric Wieser (Feb 27 2025 at 21:39):
docs#Subgroup.IsComplement might be of interest here
Alex Brodbelt (Feb 28 2025 at 09:14):
Kevin Buzzard said:
Nice!
I feel like it's golfable but I couldn't immediately see how to make it much shorter. You should probably get out of the habit of using non-terminal
simp
s though.
What do you mean? How are you simplifying otherwise? By hand? Or is there some other tactic that is preferred?
Alex Brodbelt (Feb 28 2025 at 09:17):
Eric Wieser said:
docs#Subgroup.IsComplement might be of interest here
I see - so this is where this type of result lives in mathlib!
Ruben Van de Velde (Feb 28 2025 at 09:22):
You can use simp?
and click the "try this" message
Alex Brodbelt (Feb 28 2025 at 11:06):
º
Alex Brodbelt (Feb 28 2025 at 11:06):
I see
Alex Brodbelt (Feb 28 2025 at 15:08):
To be clear, you modify it to a simp only
?
Ruben Van de Velde (Feb 28 2025 at 16:40):
Yes, exactly
Ruben Van de Velde (Feb 28 2025 at 16:41):
That means that if someone adds new lemmas for simp
to try, they don't affect your code. (This is less of an issue if simp
closes the goal, because there should be nothing else left to do for the new lemma)
Last updated: May 02 2025 at 03:31 UTC