1-- The free group on two generators as a structure value: the reduced2-- words under the reduction of their concatenation, the generators freeA3-- and freeB, the reduced words starting with a given letter, and the4-- paradoxical decomposition of the free group into those sets5-- Part of Cumulus, the Grace17 mathematics library.6-- Copyright (c) 2026 Grant Passmore.7-- Released under the Apache License 2.0. See LICENSE in the repository root.8-- Authors: Grant Passmore910module Grace.Cumulus.Algebra.Group.FreeGroup11import Words12import Coset1314-- The product of two reduced words reduces their concatenation, and the15-- inverse of a reduced word reduces its inverse word; both are graphs on16-- the reduced words.17defgraph freeMul (p ∈ reducedWords × reducedWords) : reducedWords :=18 reduce(concat(fst(p), snd(p)))19proof20obtain⟨bound, u, hu, v, hv, shape⟩:= product.membership.forward with member21have listU := reducedWords.list with hu22have listV := reducedWords.list with hv23rw [shape, fst.pair, snd.pair]24exact reduce.mem with*2526defgraph freeInv (w ∈ reducedWords) : reducedWords := reduce(inverseWord(w))27proof28have list := reducedWords.list with member29have inverse := inverseWord.closed with list30exact reduce.mem with inverse3132-- The free group on the two generators freeA = [0] and freeB = [2].33def freeGroup : Set:= Group.mk(reducedWords, freeMul, [], freeInv)34def freeA : Set:=0 :: []35def freeB : Set:=2 :: []3637-- The reduced words whose first letter is ℓ.38def startsWith (ℓ : Set) : Set:= { w ∈ reducedWords |∃ u, w = ℓ :: u }3940theorem freeGroup.carrierOf41shows Group.carrier(freeGroup) = reducedWords42proof43simp [freeGroup, Group.mk.carrier]4445theorem freeGroup.operation46shows Group.mul(freeGroup) = freeMul47proof48simp [freeGroup, Group.mk.mul]4950theorem freeGroup.unit51shows Group.one(freeGroup) = []52proof53simp [freeGroup, Group.mk.one]5455theorem freeGroup.inverse56shows Group.inv(freeGroup) = freeInv57proof58simp [freeGroup, Group.mk.inv]5960-- The product and the inverse on reduced words.61theorem freeMul.apply (u v : Set)62requires hu : u ∈ reducedWords63requires hv : v ∈ reducedWords64shows freeMul(u, v) = reduce(concat(u, v))65proof66have pair := product.pair at u, v, reducedWords, reducedWords with*67have value := freeMul.value at (u, v) with pair68simp [call2]69rw [fst.pair, snd.pair]70rfl7172theorem freeMul.mem (u v : Set)73requires hu : u ∈ reducedWords74requires hv : v ∈ reducedWords75shows freeMul(u, v) ∈ reducedWords76proof77have listU := reducedWords.list with hu78have listV := reducedWords.list with hv79rw freeMul.apply80exact reduce.mem with*8182theorem freeInv.apply (w : Set)83requires hw : w ∈ reducedWords84shows freeInv(w) = reduce(inverseWord(w))85proof86exact freeInv.value at w with hw8788theorem freeInv.mem (w : Set)89requires hw : w ∈ reducedWords90shows freeInv(w) ∈ reducedWords91proof92have list := reducedWords.list with hw93have inverse := inverseWord.closed with list94rw freeInv.apply95exact reduce.mem with inverse9697-- The free group is a group.98theorem freeGroup.group99shows Group(freeGroup)100proof101have mulFunction := freeMul.function102have invFunction := freeInv.function103have unitIn := reducedWords.nil_mem104unfold freeGroup105apply Group.intro with mulFunction, unitIn, invFunction106 . intros a ha b hb c hc107have listA := reducedWords.list with ha108have listB := reducedWords.list with hb109have listC := reducedWords.list with hc110have abIn := freeMul.mem with ha, hb111have bcIn := freeMul.mem with hb, hc112have ab := freeMul.apply with ha, hb113have bc := freeMul.apply with hb, hc114haveleft:= freeMul.apply with abIn, hc115haveright:= freeMul.apply with ha, bcIn116have leftLaw := reduce.concat_left at concat(a, b), c with*117have rightLaw := reduce.concat_right at a, concat(b, c) with*118have assoc := concat.associative at a, b, c with*119rw [left, right, ab, bc, ← leftLaw, ← rightLaw, assoc]120rfl121 . intros a ha122have listA := reducedWords.list with ha123have value := freeMul.apply with unitIn, ha124rw [value, concat.nil_left]125exact reducedWords.fixed with ha126 . intros a ha127have listA := reducedWords.list with ha128have value := freeMul.apply with ha, unitIn129rw [value, concat.nil_right]130exact reducedWords.fixed with ha131 . intros a ha132have listA := reducedWords.list with ha133have invIn := freeInv.mem with ha134have value := freeMul.apply with invIn, ha135have invValue := freeInv.apply with ha136have law := reduce.concat_left at inverseWord(a), a with*137rw [value, invValue, ← law]138exact reduce.inverse_left with listA139 . intros a ha140have listA := reducedWords.list with ha141have invIn := freeInv.mem with ha142have value := freeMul.apply with ha, invIn143have invValue := freeInv.apply with ha144have law := reduce.concat_right at a, inverseWord(a) with*145rw [value, invValue, ← law]146exact reduce.inverse_right with listA147148theorem freeA.mem149shows freeA ∈ reducedWords150proof151have letter := letter.zero_mem152have reduced := Reduced.singleton with letter153have list : List(4, 0 :: []) bytypecheck154unfold freeA155exact reducedWords.of_reduced with list, reduced156157theorem freeB.mem158shows freeB ∈ reducedWords159proof160have letter := letter.two_mem161have reduced := Reduced.singleton with letter162have list : List(4, 2 :: []) bytypecheck163unfold freeB164exact reducedWords.of_reduced with list, reduced165166-- Multiplying by a single letter pushes it onto the word.167theorem freeMul.letter (ℓ w : Set)168requires hℓ : ℓ ∈4169requires hw : w ∈ reducedWords170shows freeMul(ℓ :: [], w) = pushLetter(ℓ, w)171proof172have list := reducedWords.list with hw173have single : List(4, ℓ :: []) bytypecheck174have singleIn := reducedWords.of_reduced with single, (Reduced.singleton with hℓ)175have value := freeMul.apply with singleIn, hw176have fixed := reducedWords.fixed with hw177rw [value, concat.singleton, reduce.cons, fixed]178rfl179180-- The words starting with a letter.181theorem startsWith.subset (ℓ : Set)182shows startsWith(ℓ) ⊆ reducedWords183proof184intros w hw185have parts := startsWith.membership.forward with hw186exact parts.left187188theorem startsWith.of_reduced (ℓ : Set) (u : List(4))189requires hℓ : ℓ ∈4190requires reduced : Reduced(ℓ :: u)191shows ℓ :: u ∈ startsWith(ℓ)192proof193have list : List(4, ℓ :: u) bytypecheck194have member := reducedWords.of_reduced with list, reduced195exact startsWith.membership.backward with⟨member, u, rfl⟩196197theorem startsWith.nil_not_mem (ℓ : Set)198shows¬([] ∈ startsWith(ℓ))199proof200intro member201obtain⟨bound, u, equal⟩:= startsWith.membership.forward with member202have distinct := List.inductive.disjoint.nil.cons at ℓ, u203exact distinct with equal204205theorem startsWith.head (ℓ m : Set) (u : List(4))206requires hℓ : ℓ ∈4207requires hm : m ∈4208requires member : m :: u ∈ startsWith(ℓ)209shows m = ℓ210proof211obtain⟨bound, v, equal⟩:= startsWith.membership.forward with member212have both := List.inductive.injective.cons with equal213exact both.left214215theorem startsWith.disjoint (ℓ m : Set)216requires hℓ : ℓ ∈4217requires hm : m ∈4218requires different : ℓ ≠ m219shows Disjoint(startsWith(ℓ), startsWith(m))220proof221apply Disjoint.iff.backward222intros w hwℓ hwm223obtain⟨boundℓ, u, equalℓ⟩:= startsWith.membership.forward with hwℓ224obtain⟨boundm, v, equalm⟩:= startsWith.membership.forward with hwm225have same : ℓ :: u = m :: v bycc226have both := List.inductive.injective.cons with same227exact different with both.left228229-- Every reduced word is empty or starts with one of the four letters.230theorem reducedWords.cases (w : Set)231requires hw : w ∈ reducedWords232shows w = [] ∨∃ ℓ ∈4, w ∈ startsWith(ℓ)233proof234have list := reducedWords.list with hw235have shape := List.cases with list236cases shape with nil | cons237 . left238exact nil239 . right240obtain⟨ℓ, hℓ, u, tailList, equal⟩:= cons241rw equal at hw242refine⟨ℓ, hℓ, ?_⟩243rw equal244exact startsWith.membership.backward with⟨hw, u, rfl⟩245246-- The five pieces: the empty word and the words starting with each letter.247theorem reducedWords.decomposition248shows reducedWords =249 {[]} ∪ startsWith(0) ∪ startsWith(1) ∪ startsWith(2) ∪ startsWith(3)250proof251ext w252constructor253 . intro hw254havesplit:= reducedWords.cases with hw255casessplitwith nil | cons256 . rw nil257simp [union2.membership, singleton.membership]258 . obtain⟨ℓ, hℓ, member⟩:= cons259have letters := letter.cases with hℓ260rcases letters with zero | one | two | three261 . rw zero at member262simp [union2.membership, member]263 . rw one at member264simp [union2.membership, member]265 . rw two at member266simp [union2.membership, member]267 . rw three at member268simp [union2.membership, member]269 . intro hw270have nilSubset : {[]} ⊆ reducedWords271intros z hz272have equal := singleton.membership.forward with hz273rw equal274exact reducedWords.nil_mem275have first := union2.subset with nilSubset, (startsWith.subset at0)276have second := union2.subset with first, (startsWith.subset at1)277have third := union2.subset with second, (startsWith.subset at2)278have fourth := union2.subset with third, (startsWith.subset at3)279exact fourth with w, hw280281-- Translating the words starting with the inverse of ℓ by the letter ℓ282-- gives exactly the reduced words not starting with ℓ.283theorem leftCoset.letter (ℓ m : Set)284requires hℓ : ℓ ∈4285requires hm : m ∈4286requires inverse : m = inverseLetter(ℓ)287shows leftCoset(freeGroup, ℓ :: [], startsWith(m)) = reducedWords ∖ startsWith(ℓ)288proof289have cancel : cancels(ℓ, m) = Bool.true290rw inverse291exact cancels.self_inverse with hℓ292have cancelBack : cancels(m, ℓ) = Bool.true293rw inverse294exact cancels.inverse_self with hℓ295ext w296constructor297 . intro hw298obtain⟨bound, h, hh, equal⟩:= leftCoset.membership.forward with hw299rw freeGroup.operation at equal300have hIn := startsWith.subset at m with h, hh301obtain⟨boundH, u, hShape⟩:= startsWith.membership.forward with hh302have listH := reducedWords.list with hIn303rw hShape at listH304have tailList := List.tail_list with listH305have reducedH := reducedWords.reduced with hIn306rw hShape at reducedH307have reducedU := Reduced.tail with hm, reducedH308have pushed := freeMul.letter with hℓ, hIn309rw [hShape, pushLetter.cancel] at pushed310rw [equal, hShape, pushed]311apply difference.membership.backward312constructor313 . exact reducedWords.of_reduced with tailList, reducedU314 . intro inLetter315obtain⟨boundU, v, uShape⟩:= startsWith.membership.forward with inLetter316rw uShape at reducedH317rw uShape at tailList318have listV := List.tail_list with tailList319have parts := Reduced.cons_cons.forward with hm, hℓ, reducedH320have distinct := Bool.inductive.disjoint.false.true321have mixed : Bool.false = Bool.true bycc322exact distinct with mixed323 . intro hw324obtain⟨hwIn, notℓ⟩:= difference.membership.forward with hw325have listW := reducedWords.list with hwIn326have reducedW := reducedWords.reduced with hwIn327have fits : fitsTest(m, w) = Bool.true328have shape := List.cases with listW329cases shape with nil | cons330 . rw nil331exact fitsTest.nil with hm332 . obtain⟨y, hy, ys, ysList, consShape⟩:= cons333have headDifferent : y ≠ ℓ334intro same335apply notℓ336rw [consShape, same]337rw [consShape, same] at reducedW338exact startsWith.of_reduced with hℓ, reducedW339have keep : cancels(m, y) = Bool.false340apply cancels.false_iff.backward with hm, hy341rw inverse342rw inverseLetter.involutive343exact headDifferent344have boolean := cancels.boolean at m, y345rw [consShape, fitsTest.cons]346exact not.true_iff.backward with boolean, keep347have reducedH := Reduced.cons_iff.backward with hm, ⟨fits, reducedW⟩348have hIn := startsWith.of_reduced with hm, reducedH349have listH : List(4, m :: w) bytypecheck350have hCarrier := reducedWords.of_reduced with listH, reducedH351have pushed := freeMul.letter with hℓ, hCarrier352rw pushLetter.cancel at pushed353apply leftCoset.membership.backward354rw freeGroup.carrierOf355refine⟨hwIn, m :: w, hIn, ?_⟩356rw freeGroup.operation357 symm358exact pushed359360-- The paradoxical decomposition of the free group: the words starting361-- with a together with the translate by a of the words starting with a⁻¹362-- exhaust the group, and likewise for b.363theorem freeGroup.decomposition_a364shows startsWith(0) ∪ leftCoset(freeGroup, freeA, startsWith(1)) = reducedWords ∧365 Disjoint(startsWith(0), leftCoset(freeGroup, freeA, startsWith(1)))366proof367have zero := letter.zero_mem368have one := letter.one_mem369have inverse : 1= inverseLetter(0)370 symm371exact inverseLetter.zero372have translate := leftCoset.letter with zero, one, inverse373have value : freeA =0 :: [] bysimp [freeA]374rw [value, translate]375constructor376 . exact difference.union2_of_subset with (startsWith.subset at0)377 . have disjoint := difference.disjoint at reducedWords, startsWith(0)378exact Disjoint.symmetric with disjoint379380theorem freeGroup.decomposition_b381shows startsWith(2) ∪ leftCoset(freeGroup, freeB, startsWith(3)) = reducedWords ∧382 Disjoint(startsWith(2), leftCoset(freeGroup, freeB, startsWith(3)))383proof384have two := letter.two_mem385have three := letter.three_mem386have inverse : 3= inverseLetter(2)387 symm388exact inverseLetter.two389have translate := leftCoset.letter with two, three, inverse390have value : freeB =2 :: [] bysimp [freeB]391rw [value, translate]392constructor393 . exact difference.union2_of_subset with (startsWith.subset at2)394 . have disjoint := difference.disjoint at reducedWords, startsWith(2)395exact Disjoint.symmetric with disjoint396