1-- Bundled groups: a group as one structure of its carrier, operation, unit,2-- and inverse, the laws of a group under their standard names, and the3-- group rewrite set4-- Part of Cumulus, the Grace17 mathematics library.5-- Copyright (c) 2026 Grant Passmore.6-- Released under the Apache License 2.0. See LICENSE in the repository root.7-- Authors: Grant Passmore89module Grace.Cumulus.Algebra.Group.Basic10import Core1112-- A group is a structure of its carrier, its operation graph, its unit, and13-- its inverse graph, built by Group.mk(A, m, e, i) and read back by the14-- projections G.carrier, G.mul, G.one, and G.inv. The operation applies to15-- two arguments, G.mul(x, y), and the inverse as a function, G.inv(x).16-- Group(G) says that G is such a structure whose data satisfy the laws17-- below, under their standard names; Group.Data(G) is the shape alone, and18-- Group.intro builds a group from its four pieces and the laws.19structure Group20| carrier : Set21| mul : carrier × carrier → carrier22| one : carrier23| inv : carrier → carrier24where25 mul_assoc : ∀ a b c ∈ carrier, mul(mul(a, b), c) = mul(a, mul(b, c))26 one_mul : ∀ a ∈ carrier, mul(one, a) = a27 mul_one : ∀ a ∈ carrier, mul(a, one) = a28 inv_mul : ∀ a ∈ carrier, mul(inv(a), a) = one29 mul_inv : ∀ a ∈ carrier, mul(a, inv(a)) = one3031-- The projection laws of a constructed group as one rewrite set.32tactic group_projections :=simp [Group.mk.carrier, Group.mk.mul, Group.mk.one, Group.mk.inv]3334-- The monoid and the abelian group as properties of the same structure:35-- Monoid(G) is the unbundled monoid at the projections, and AbelianGroup(G)36-- is a group whose operation commutes. IsMonoid(A, m, e), IsGroup(A, m, e, i),37-- and IsAbelianGroup(A, m, e, i) remain the forms over separate pieces.38predicate Monoid (G : Set) := Group.Data(G) ∧ IsMonoid(G.carrier, G.mul, G.one)39predicate AbelianGroup (G : Set) := Group(G) ∧ Commutative(G.carrier, G.mul)4041-- The operation is written a * b and the inverse a⁻¹ wherever a hypothesis42-- in scope supplies the group; the operands' membership in G.carrier43-- selects the group when several are in scope. Under the same hypotheses a44-- binder (a : G) is a set variable with a ∈ G.carrier.45notationinfixl70"*"=> call2(G.mul, _, _) viahypothesis Monoid(G) for G.carrier46notationinfixl70"*"=> call2(G.mul, _, _) viahypothesis Group(G) for G.carrier47notationinfixl70"*"=> call2(G.mul, _, _) viahypothesis AbelianGroup(G) for G.carrier48notationpostfix90"⁻¹"=>apply(G.inv, _) viahypothesis Group(G) for G.carrier49notationpostfix90"⁻¹"=>apply(G.inv, _) viahypothesis AbelianGroup(G) for G.carrier5051-- Bridges between the structure and the forms over separate pieces.52theorem Group.parts (G : Set)53requires group : Group(G)54shows IsGroup(G.carrier, G.mul, G.one, G.inv)55proof56obtain⟨shape, mulF, oneIn, invF, assoc, oneMul, mulOne, invMul, mulInv⟩:= group57unfold IsGroup58constructor59 . unfold IsMonoid60constructor61 . unfold IsSemigroup62constructor63 . exact mulF64 . unfold Associative65exact assoc66 . unfold Identity67refine⟨oneIn, ?_⟩68intros x xIn69haveleft:= oneMul with x, xIn70haveright:= mulOne with x, xIn71exact⟨left, right⟩72 . unfold Inverse73refine⟨invF, ?_⟩74intros x xIn75haveleft:= invMul with x, xIn76haveright:= mulInv with x, xIn77exact⟨left, right⟩7879theorem Group.of_parts (A m e i : Set)80requires group : IsGroup(A, m, e, i)81shows Group(Group.mk(A, m, e, i))82proof83have monoid := IsGroup.monoid with group84have mulF := IsGroup.magma with group85have assoc := IsMonoid.associative with monoid86have oneIn := IsMonoid.unit_in_carrier with monoid87obtain⟨invF, inverses⟩:= IsGroup.inverse with group88apply Group.intro89 . exact mulF90 . exact oneIn91 . exact invF92 . unfold Associative at assoc93exact assoc94 . intros x xIn95exact IsMonoid.left_identity with monoid, xIn96 . intros x xIn97exact IsMonoid.right_identity with monoid, xIn98 . intros x xIn99have both := inverses with x, xIn100exact both.left101 . intros x xIn102have both := inverses with x, xIn103exact both.right104105theorem Monoid.parts (G : Set)106requires monoid : Monoid(G)107shows IsMonoid(G.carrier, G.mul, G.one)108proof109obtain⟨shape, laws⟩:= monoid110exact laws111112theorem Monoid.of_parts (A m e i : Set)113requires monoid : IsMonoid(A, m, e)114shows Monoid(Group.mk(A, m, e, i))115proof116have shape := Group.mk.data at A, m, e, i117unfold Monoid118 group_projections119120theorem AbelianGroup.parts (G : Set)121requires abelian : AbelianGroup(G)122shows IsAbelianGroup(G.carrier, G.mul, G.one, G.inv)123proof124obtain⟨group, commutative⟩:= abelian125have parts := Group.parts with group126unfold IsAbelianGroup127exact⟨parts, commutative⟩128129theorem AbelianGroup.of_parts (A m e i : Set)130requires abelian : IsAbelianGroup(A, m, e, i)131shows AbelianGroup(Group.mk(A, m, e, i))132proof133have group := Group.of_parts with (IsAbelianGroup.group with abelian)134have commutative := IsAbelianGroup.commutative with abelian135unfold AbelianGroup136 group_projections137138theorem Group.to_monoid (G : Set)139requires group : Group(G)140shows Monoid(G)141proof142obtain⟨shape, rest⟩:= group143have parts := Group.parts with group144unfold Monoid145exact⟨shape, IsGroup.monoid with parts⟩146147theorem AbelianGroup.to_group (G : Set)148requires abelian : AbelianGroup(G)149shows Group(G)150proof151obtain⟨group, commutative⟩:= abelian152exact group153154-- A group is the constructor applied to its projections.155theorem Group.eta_of_group (G : Set)156requires group : Group(G)157shows G = Group.mk(G.carrier, G.mul, G.one, G.inv)158proof159obtain⟨shape, rest⟩:= group160exact Group.eta with shape161162section GroupLaws163variable (G : Set)164hypothesis group : Group(G)165166-- Closure: the operation, unit, and inverse stay in the carrier. These are167-- instances, so the membership of a compound term is synthesized.168instance Group.mul_mem (a b : G)169shows a * b ∈ G170proof171have monoid := IsGroup.monoid with (Group.parts with group)172exact IsMonoid.closed with monoid, *173174instance Group.one_mem175shows G.one ∈ G176proof177have monoid := IsGroup.monoid with (Group.parts with group)178exact IsMonoid.unit_in_carrier with monoid179180instance Group.inv_mem (a : G)181shows a⁻¹ ∈ G182proof183have parts := Group.parts with group184exact IsGroup.inverse_closed with parts, *185186theorem Group.operation_function187shows G.mul : G.carrier × G.carrier → G.carrier188proof189have monoid := IsGroup.monoid with (Group.parts with group)190have semigroup := IsMonoid.semigroup with monoid191exact IsSemigroup.magma with semigroup192193theorem Group.inverse_function194shows G.inv : G.carrier → G.carrier195proof196obtain⟨function, laws⟩:= IsGroup.inverse with (Group.parts with group)197exact function198199-- The laws, under their standard names: the familiar underscore names, and200-- the dotted Group.inv_mul, Group.mul_inv, and Group.inv_involutive.201theorem mul_assoc (a b c : G)202shows a * b * c = a * (b * c)203proof204have monoid := IsGroup.monoid with (Group.parts with group)205have associative := IsMonoid.associative with monoid206exact Associative.law with associative, *207208theorem one_mul (a : G)209shows G.one * a = a210proof211have monoid := IsGroup.monoid with (Group.parts with group)212exact IsMonoid.left_identity with monoid, *213214theorem mul_one (a : G)215shows a * G.one = a216proof217have monoid := IsGroup.monoid with (Group.parts with group)218exact IsMonoid.right_identity with monoid, *219220theorem Group.inv_mul (a : G)221shows a⁻¹ * a = G.one222proof223have parts := Group.parts with group224exact IsGroup.inverse_left with parts, *225226theorem Group.mul_inv (a : G)227shows a * a⁻¹ = G.one228proof229have parts := Group.parts with group230exact IsGroup.inverse_right with parts, *231232theorem inv_mul_cancel_left (a b : G)233shows a⁻¹ * (a * b) = b234proof235rw [← mul_assoc, Group.inv_mul, one_mul]236rfl237238theorem mul_inv_cancel_left (a b : G)239shows a * (a⁻¹ * b) = b240proof241rw [← mul_assoc, Group.mul_inv, one_mul]242rfl243244theorem mul_inv_cancel_right (a b : G)245shows a * b * b⁻¹ = a246proof247rw [mul_assoc, Group.mul_inv, mul_one]248rfl249250theorem inv_mul_cancel_right (a b : G)251shows a * b⁻¹ * b = a252proof253rw [mul_assoc, Group.inv_mul, mul_one]254rfl255256theorem mul_left_cancel (a b c : G)257requires equal : a * b = a * c258shows b = c259proof260calc261 b = a⁻¹ * (a * b) :=byrw inv_mul_cancel_left262 _ = a⁻¹ * (a * c) :=byrw equal263 _ = c :=byrw inv_mul_cancel_left264265theorem mul_right_cancel (a b c : G)266requires equal : a * b = c * b267shows a = c268proof269calc270 a = a * b * b⁻¹ :=byrw mul_inv_cancel_right271 _ = c * b * b⁻¹ :=byrw equal272 _ = c :=byrw mul_inv_cancel_right273274theorem mul_right_inj (a b c : G)275shows a * b = a * c ↔ b = c276proof277constructor278 . intro equal279exact mul_left_cancel with*280 . intro equal281rw equal282rfl283284theorem mul_left_inj (a b c : G)285shows a * b = c * b ↔ a = c286proof287constructor288 . intro equal289exact mul_right_cancel with*290 . intro equal291rw equal292rfl293294theorem inv_one295shows G.one⁻¹ = G.one296proof297have cancel : G.one⁻¹ * G.one = G.one := Group.inv_mul with*298 rwa mul_one at cancel299300theorem eq_inv_of_mul_eq_one_left (a b : G)301requires equal : a * b = G.one302shows a = b⁻¹303proof304calc305 a = a * b * b⁻¹ :=byrw mul_inv_cancel_right306 _ = b⁻¹ :=byrw [equal, one_mul]307308theorem eq_inv_of_mul_eq_one_right (a b : G)309requires equal : a * b = G.one310shows b = a⁻¹311proof312calc313 b = a⁻¹ * (a * b) :=byrw inv_mul_cancel_left314 _ = a⁻¹ :=byrw [equal, mul_one]315316theorem inv_eq_of_mul_eq_one_right (a b : G)317requires equal : a * b = G.one318shows a⁻¹ = b319proof320 symm321exact eq_inv_of_mul_eq_one_right with*322323theorem inv_inv (a : G)324shows (a⁻¹)⁻¹ = a325proof326have cancel : a⁻¹ * a = G.one := Group.inv_mul with*327exact inv_eq_of_mul_eq_one_right with*328329theorem Group.inv_involutive (a : G)330shows (a⁻¹)⁻¹ = a331proof332exact inv_inv with*333334theorem mul_inv_rev (a b : G)335shows (a * b)⁻¹ = b⁻¹ * a⁻¹336proof337have product : a * b * (b⁻¹ * a⁻¹) = G.one338rw [mul_assoc, mul_inv_cancel_left, Group.mul_inv]339rfl340exact inv_eq_of_mul_eq_one_right with*341342theorem mul_eq_one_iff_eq_inv (a b : G)343shows a * b = G.one ↔ a = b⁻¹344proof345constructor346 . intro equal347exact eq_inv_of_mul_eq_one_left with*348 . intro equal349rw [equal, Group.inv_mul]350rfl351352theorem mul_eq_one_iff_inv_eq (a b : G)353shows a * b = G.one ↔ a⁻¹ = b354proof355constructor356 . intro equal357exact inv_eq_of_mul_eq_one_right with*358 . intro equal359rw [← equal, Group.mul_inv]360rfl361362theorem inv_mul_eq_one (a b : G)363shows a⁻¹ * b = G.one ↔ a = b364proof365have criterion : a⁻¹ * b = G.one ↔ (a⁻¹)⁻¹ = b := mul_eq_one_iff_inv_eq with*366 rwa inv_inv at criterion367368theorem mul_inv_eq_one (a b : G)369shows a * b⁻¹ = G.one ↔ a = b370proof371have criterion : a * b⁻¹ = G.one ↔ a = (b⁻¹)⁻¹ := mul_eq_one_iff_eq_inv with*372 rwa inv_inv at criterion373374theorem inv_inj (a b : G)375shows a⁻¹ = b⁻¹ ↔ a = b376proof377constructor378 . intro equal379have twiceA : (a⁻¹)⁻¹ = a := inv_inv with*380have twiceB : (b⁻¹)⁻¹ = b := inv_inv with*381cc382 . intro equal383rw equal384rfl385386theorem inv_eq_one (a : G)387shows a⁻¹ = G.one ↔ a = G.one388proof389have criterion : a⁻¹ = G.one⁻¹ ↔ a = G.one := inv_inj with*390 rwa inv_one at criterion391392theorem mul_self_eq_self (a : G)393shows a * a = a ↔ a = G.one394proof395constructor396 . intro idempotent397calc398 a = a⁻¹ * (a * a) :=byrw inv_mul_cancel_left399 _ = G.one :=byrw [idempotent, Group.inv_mul]400 . intro equal401rw [equal, one_mul]402rfl403404theorem mul_inv_eq_iff_eq_mul (a b c : G)405shows a * b⁻¹ = c ↔ a = c * b406proof407constructor408 . intro equal409rw [← equal, inv_mul_cancel_right]410rfl411 . intro equal412rw [equal, mul_inv_cancel_right]413rfl414415theorem eq_inv_mul_iff_mul_eq (a b c : G)416shows a = b⁻¹ * c ↔ b * a = c417proof418constructor419 . intro equal420rw [equal, mul_inv_cancel_left]421rfl422 . intro equal423rw [← equal, inv_mul_cancel_left]424rfl425426theorem inv_mul_eq_iff_eq_mul (a b c : G)427shows a⁻¹ * b = c ↔ b = a * c428proof429constructor430 . intro equal431rw [← equal, mul_inv_cancel_left]432rfl433 . intro equal434rw [equal, inv_mul_cancel_left]435rfl436437theorem eq_mul_inv_iff_mul_eq (a b c : G)438shows a = b * c⁻¹ ↔ a * c = b439proof440constructor441 . intro equal442rw [equal, inv_mul_cancel_right]443rfl444 . intro equal445rw [← equal, mul_inv_cancel_right]446rfl447448end GroupLaws449450-- The group rewrite set: associativity to the right, the unit and inverse451-- cancellations, each applied where its operands are in the carrier.452tactic group_simp :=simp [mul_assoc, one_mul, mul_one, Group.inv_mul, Group.mul_inv, inv_inv, inv_one, mul_inv_rev, inv_mul_cancel_left, mul_inv_cancel_left, mul_inv_cancel_right, inv_mul_cancel_right]453454section AbelianLaws455variable (G : Set)456hypothesis abelian : AbelianGroup(G)457458theorem mul_comm (a b : G)459shows a * b = b * a460proof461have commutative := IsAbelianGroup.commutative with (AbelianGroup.parts with abelian)462exact Commutative.law with commutative, *463464theorem mul_left_comm (a b c : G)465shows a * (b * c) = b * (a * c)466proof467have group := AbelianGroup.to_group with abelian468have swap : a * b = b * a := mul_comm with*469rw [← mul_assoc, swap, mul_assoc]470rfl471472theorem mul_right_comm (a b c : G)473shows a * b * c = a * c * b474proof475have group := AbelianGroup.to_group with abelian476have swap : b * c = c * b := mul_comm with*477rw [mul_assoc, swap, ← mul_assoc]478rfl479480theorem mul_mul_mul_comm (a b c d : G)481shows a * b * (c * d) = a * c * (b * d)482proof483have group := AbelianGroup.to_group with abelian484have swap : b * (c * d) = c * (b * d) := mul_left_comm with*485rw [mul_assoc, swap, ← mul_assoc]486rfl487488theorem mul_inv (a b : G)489shows (a * b)⁻¹ = a⁻¹ * b⁻¹490proof491have group := AbelianGroup.to_group with abelian492have swap : b⁻¹ * a⁻¹ = a⁻¹ * b⁻¹ := mul_comm with*493rw [mul_inv_rev, swap]494rfl495496end AbelianLaws497