Skip to the content.
← Integers example Index Next: Accessing the fields →

intGroup is abelian ($a + b = b + a$), so it never tests the distinction between id_left/id_right or inv_left/inv_right. In a commutative group these coincide, which might suggest that the left/right split in Group’s definition is merely overly careful. It is not: the following is a small, fully concrete, genuinely non-abelian group, built the same way intGroup was, field by field.

The carrier: bijections of a 3-element set

The symmetric group $S_3$ consists of all bijections (permutations) of a 3-element set, under composition. We represent a permutation of Fin 3 := {0, 1, 2} as a bijective function bundled with its own inverse and the proofs that they cancel:

structure Perm3 where
  toFun : Fin 3  Fin 3
  invFun : Fin 3  Fin 3
  left_inv :  x, invFun (toFun x) = x
  right_inv :  x, toFun (invFun x) = x

This is the same “bundle data with the proofs that make it well-behaved” pattern as Group itself. Perm3 carries not only a function but also the proof that the function is invertible, since an arbitrary Fin 3 → Fin 3 need not be a bijection at all.

The group operation: composition

def Perm3.comp (f g : Perm3) : Perm3 where
  toFun := f.toFun  g.toFun
  invFun := g.invFun  f.invFun
  left_inv := by
    intro x
    show g.invFun (f.invFun (f.toFun (g.toFun x))) = x
    rw [f.left_inv]
    exact g.left_inv x
  right_inv := by
    intro x
    show f.toFun (g.toFun (g.invFun (f.invFun x))) = x
    rw [g.right_inv]
    exact f.right_inv x

Perm3.comp f g composes f after g (apply g.toFun first, then f.toFun). This is the standard function-composition convention. Its inverse composes the two inverses in the opposite order (g.invFun ∘ f.invFun), which is exactly $(fg)^{-1} = g^{-1}f^{-1}$, the same “reverse the order” fact Chapter 7’s Theorem 3 (inv_op) proves abstractly for every group. This construction shows concretely why the fact holds: to undo “first $g$, then $f$,” one must first undo $f$, then undo $g$.

def Perm3.identity : Perm3 where
  toFun := fun x => x
  invFun := fun x => x
  left_inv := fun _ => rfl
  right_inv := fun _ => rfl

Perm3.identity is the identity permutation: it fixes every point, hence both of its proof fields are immediate by rfl.

def Perm3.inv (f : Perm3) : Perm3 where
  toFun := f.invFun
  invFun := f.toFun
  left_inv := f.right_inv
  right_inv := f.left_inv

Perm3.inv inverts a permutation by swapping its toFun and invFun, and it correspondingly swaps which proof field (left_inv or right_inv) plays which role, since inverting a bijection simply swaps which direction counts as “forward.”

Two concrete permutations, and a computed proof they do not commute

-- Swap 0 and 1, leave 2 fixed.
def swap01 : Perm3 where
  toFun := fun x => match x with
    | 0 => 1 | 1 => 0 | 2 => 2
  invFun := fun x => match x with
    | 0 => 1 | 1 => 0 | 2 => 2
  left_inv := by intro x; match x with | 0 => rfl | 1 => rfl | 2 => rfl
  right_inv := by intro x; match x with | 0 => rfl | 1 => rfl | 2 => rfl

swap01 is the permutation that swaps 0 and 1 while leaving 2 fixed.

-- The 3-cycle 0 → 1 → 2 → 0.
def cycle012 : Perm3 where
  toFun := fun x => match x with
    | 0 => 1 | 1 => 2 | 2 => 0
  invFun := fun x => match x with
    | 0 => 2 | 1 => 0 | 2 => 1
  left_inv := by intro x; match x with | 0 => rfl | 1 => rfl | 2 => rfl
  right_inv := by intro x; match x with | 0 => rfl | 1 => rfl | 2 => rfl

cycle012 is the 3-cycle sending $0 \to 1 \to 2 \to 0$.

#eval (Perm3.comp swap01 cycle012).toFun 0   -- 0
#eval (Perm3.comp cycle012 swap01).toFun 0   -- 2

Both compositions send 0 somewhere, but to different places: applying cycle012 then swap01 sends $0 \to 1 \to 0$, while applying swap01 then cycle012 sends $0 \to 0 \to 1$. Concretely, #eval reports 0 for the first and 2 for the second. This is directly computed evidence that Perm3.comp swap01 cycle012 ≠ Perm3.comp cycle012 swap01; in other words, this group is genuinely non-abelian. This is exactly the kind of “compute a counterexample” move Chapter 8 uses again for matrices. It is cheaper than any hand-written non-commutativity proof, and it yields, for free, the specific pair of elements that fail to commute.

Assembling Group Perm3

theorem Perm3.ext {f g : Perm3} (h :  x, f.toFun x = g.toFun x)
    (h' :  x, f.invFun x = g.invFun x) : f = g := by
  cases f
  cases g
  simp only [mk.injEq]
  constructor
  · funext x; exact h x
  · funext x; exact h' x

def perm3Group : Group Perm3 where
  op := Perm3.comp
  id := Perm3.identity
  inv := Perm3.inv
  assoc := by
    intro f g h
    apply Perm3.ext
    · intro x; rfl
    · intro x; rfl
  id_left := by
    intro f
    apply Perm3.ext
    · intro x; rfl
    · intro x; rfl
  id_right := by
    intro f
    apply Perm3.ext
    · intro x; rfl
    · intro x; rfl
  inv_left := by
    intro f
    apply Perm3.ext
    · intro x; exact f.left_inv x
    · intro x; exact f.left_inv x
  inv_right := by
    intro f
    apply Perm3.ext
    · intro x; exact f.right_inv x
    · intro x; exact f.right_inv x

Perm3.ext is a small helper (an extensionality lemma, in the same spirit as Chapter 8’s Mat2.mk.injEq-based reasoning): two Perm3s are equal exactly when their toFuns agree everywhere and their invFuns agree everywhere, since those are Perm3’s only two fields (the proof fields do not matter, by proof irrelevance, Chapter 5). Each Group field is then proved by reducing to this extensionality check and confirming both functions involved agree pointwise. Most cases are rfl directly (both sides compute to the same function once unfolded), and inv_left/ inv_right cite exactly f.left_inv/f.right_inv, the proof obligations already bundled into Perm3 itself.

Mathematical reading. Perm3 (with composition) is $S_3$, the symmetric group on three letters. It is the smallest non-abelian group (order $6$) and the standard first example in any course covering non-commutative groups. swap01 and cycle012 here are, respectively, a transposition and a 3-cycle. Together they generate all of $S_3$, exactly as in the usual presentation $S_3 = \langle r, s \mid r^3 = s^2 = e,\ srs = r^{-1} \rangle$, with $r$ = cycle012 and $s$ = swap01.

Mathlib equivalent. All of Perm3/Perm3.comp/Perm3.ext/ perm3Group above exists to build one thing: “the group of bijections of a 3-element set.” Mathlib’s ready-made model of exactly that is Equiv.Perm, already a Group instance for any type:

example : Group (Equiv.Perm (Fin 3)) := inferInstance

-- Swap 0 and 1, leave 2 fixed — the Mathlib analogue of `swap01`.
def swap01' : Equiv.Perm (Fin 3) := Equiv.swap 0 1

-- The 3-cycle 0 → 1 → 2 → 0 — the Mathlib analogue of `cycle012`.
def cycle012' : Equiv.Perm (Fin 3) := finRotate 3

#eval (swap01' * cycle012') 0   -- 0
#eval (cycle012' * swap01') 0    -- 2

No Perm3 bundle, no hand-written extensionality lemma, and no field-by-field Group construction are needed: Equiv.Perm (Fin 3) (the type of bijections Fin 3 ≃ Fin 3) is already known to be a group, Equiv.swap and finRotate are Mathlib’s own constructors for a transposition and a rotation, and * is the already-registered group operation (composition, matching Perm3.comp’s convention). The two #evals are the same “compute a witness of non-commutativity” move as swap01/cycle012 above, now applied to the library’s own $S_3$.

Next

Continue to Accessing the fields.


← Integers example Index Next: Accessing the fields →
Try Lean
Lean playground · v1.4.18