{-# OPTIONS --cubical #-}
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.GroupoidLaws as GL
open import Cubical.Foundations.Structure
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Pointed hiding (⋆)
open import Cubical.Foundations.Function
open import Cubical.Foundations.Isomorphism
open import Cubical.Data.Sigma
open import Cubical.Algebra.Semigroup
open import Cubical.Algebra.Monoid
open import Cubical.Algebra.Group
open import Cubical.Algebra.Group.Morphisms
open import Cubical.Algebra.Group.MorphismProperties
open import Cubical.Relation.Binary hiding (Rel)
open import Cubical.HITs.SetQuotients as SQ
private variable
ℓ ℓ' : Level
module _ (G : Group ℓ) where
open GroupStr (str G)
open import Cubical.HITs.EilenbergMacLane1 as EM
loop-id : emloop 1g ≡ refl
loop-id =
emloop 1g ≡⟨ lUnit (emloop 1g) ⟩
refl ∙ emloop 1g ≡⟨ cong (_∙ emloop 1g) (sym (lCancel (emloop 1g)) ) ⟩
(emloop 1g ⁻¹ ∙ emloop 1g) ∙ emloop 1g ≡⟨ sym (assoc _ _ _) ⟩
emloop 1g ⁻¹ ∙ (emloop 1g ∙ emloop 1g) ≡⟨ cong (sym (emloop 1g) ∙_) (sym (emloop-comp G 1g 1g) ∙ cong emloop (·IdL 1g)) ⟩
emloop 1g ⁻¹ ∙ emloop 1g ≡⟨ rCancel _ ⟩
refl ∎
subst2≡ : {A : Type ℓ} {x x' y y' : A} (p : x ≡ x') (q : y ≡ y') (r : x ≡ y) → subst2 _≡_ p q r ≡ sym p ∙ r ∙ q
subst2≡ p q r = J (λ _ p → subst2 _≡_ p q r ≡ sym p ∙ r ∙ q) lem p
where
lem'' : subst2 _≡_ refl refl r ≡ r
lem'' = transportRefl r
lem' : subst2 _≡_ refl q r ≡ r ∙ q
lem' = J (λ _ q → subst2 _≡_ refl q r ≡ r ∙ q) (lem'' ∙ rUnit r) q
lem : subst2 _≡_ refl q r ≡ sym refl ∙ r ∙ q
lem = lem' ∙ cong₂ _∙_ (lUnit r) refl ∙ sym (assoc _ _ _)
subst2≡Refl : {A : Type ℓ} {x y z : A} (p : y ≡ x) (q : y ≡ z) → subst2 _≡_ p q refl ≡ sym p ∙ q
subst2≡Refl p q =
subst2 _≡_ p q refl ≡⟨ subst2≡ p q refl ⟩
sym p ∙ refl ∙ q ≡⟨ cong₂ _∙_ refl (sym (lUnit q)) ⟩
sym p ∙ q ∎
record Span (X Y : Type ℓ) : Type (ℓ-max ℓ (ℓ-suc ℓ')) where
field
total : Type ℓ'
src : total → X
tgt : total → Y
Graph : (X : Type ℓ) → Type (ℓ-max ℓ (ℓ-suc ℓ'))
Graph {ℓ' = ℓ'} X = Span {ℓ' = ℓ'} X X
module _ (G : Group ℓ) where
open Span
open GroupStr (str G)
record isCongruence (_∼_ : ⟨ G ⟩ → ⟨ G ⟩ → Type ℓ) : Type ℓ where
field
equivalence : BinaryRelation.isEquivRel _∼_
preservesProd : {x x' y y' : ⟨ G ⟩} → x ∼ x' → y ∼ y' → (x · y) ∼ (x' · y')
open isCongruence public
Congruence : Type _
Congruence = Σ (⟨ G ⟩ → ⟨ G ⟩ → Type ℓ) isCongruence
isReflexive : (R : Congruence) {x : ⟨ G ⟩} → fst R x x
isReflexive R {x} = snd R .equivalence .BinaryRelation.isEquivRel.reflexive x
isTransitive : (R : Congruence) {x y z : ⟨ G ⟩} → fst R x y → fst R y z → fst R x z
isTransitive R p q = snd R .equivalence .BinaryRelation.isEquivRel.transitive _ _ _ p q
isSymmetric : (R : Congruence) {x y : ⟨ G ⟩} → fst R x y → fst R y x
isSymmetric R p = snd R .equivalence .BinaryRelation.isEquivRel.symmetric _ _ p
preservesProduct : (R : Congruence) {x x' y y' : ⟨ G ⟩} → fst R x x' → fst R y y' → fst R (x · y) (x' · y')
preservesProduct R = snd R .preservesProd
preserves≡ : (R : Congruence) → {x y : ⟨ G ⟩} → x ≡ y → fst R x y
preserves≡ R {x = x} p = subst (fst R x) p (isReflexive R)
preservesInverse : (R : Congruence) → {x y : ⟨ G ⟩} → fst R x y → fst R (inv x) (inv y)
preservesInverse R {x} {y} p =
preserves≡ R (sym (·IdL (inv x))) ··
preserves≡ R (cong (λ y → y · inv x) (sym (·InvL y))) ··
preserves≡ R (sym (·Assoc _ _ _)) ··
preservesProduct R (isReflexive R) (preservesProduct R (isSymmetric R p) (isReflexive R)) ··
preservesProduct R (isReflexive R) (preserves≡ R (·InvR x)) ··
preserves≡ R (·IdR (inv y))
where
infixr 30 _··_
_··_ = isTransitive R
module _ (R : Graph {ℓ' = ℓ} ⟨ G ⟩) where
data freeCongruence : ⟨ G ⟩ → ⟨ G ⟩ → Type ℓ where
fcBase : (r : total R) → freeCongruence (src R r) (tgt R r)
fcRefl : {x : ⟨ G ⟩} → freeCongruence x x
fcTrans : {x y z : ⟨ G ⟩} → freeCongruence x y → freeCongruence y z → freeCongruence x z
fcSym : {x y : ⟨ G ⟩} → freeCongruence x y → freeCongruence y x
fcProd : {x x' y y' : ⟨ G ⟩} → freeCongruence x x' → freeCongruence y y' → freeCongruence (x · y) (x' · y')
freeCongruenceIsCongruence : isCongruence freeCongruence
BinaryRelation.isEquivRel.reflexive (equivalence freeCongruenceIsCongruence) _ = fcRefl
BinaryRelation.isEquivRel.symmetric (equivalence freeCongruenceIsCongruence) _ _ = fcSym
BinaryRelation.isEquivRel.transitive (equivalence freeCongruenceIsCongruence) _ _ _ = fcTrans
preservesProd freeCongruenceIsCongruence = fcProd
freeCongruenceCongruence : Congruence
freeCongruenceCongruence = freeCongruence , freeCongruenceIsCongruence
module _ (R : Congruence) where
quotient : Group ℓ
quotient = (⟨ G ⟩ / fst R) , grp
where
open isCongruence (snd R)
grp : GroupStr (⟨ G ⟩ / fst R)
GroupStr.1g grp = [ 1g ]
GroupStr._·_ grp x y = rec2 squash/ (λ x y → [ x · y ]) (λ _ _ _ r → eq/ _ _ (preservesProduct R r (isReflexive R))) (λ _ _ _ r → eq/ _ _ (preservesProduct R (isReflexive R) r)) x y
GroupStr.inv grp x = SQ.rec squash/ (λ x → [ inv x ]) (λ _ _ r → eq/ _ _ (preservesInverse R r)) x
IsSemigroup.is-set (IsMonoid.isSemigroup (IsGroup.isMonoid (GroupStr.isGroup grp))) = squash/
IsSemigroup.·Assoc (IsMonoid.isSemigroup (IsGroup.isMonoid (GroupStr.isGroup grp))) = SQ.elimProp3 (λ _ _ _ → squash/ _ _) λ x y z → cong [_] (·Assoc x y z)
IsMonoid.·IdR (IsGroup.isMonoid (GroupStr.isGroup grp)) = SQ.elimProp (λ _ → squash/ _ _) λ x → cong [_] (·IdR x)
IsMonoid.·IdL (IsGroup.isMonoid (GroupStr.isGroup grp)) = SQ.elimProp (λ _ → squash/ _ _) λ x → cong [_] (·IdL x)
IsGroup.·InvR (GroupStr.isGroup grp) = SQ.elimProp (λ _ → squash/ _ _) λ x → cong [_] (·InvR x)
IsGroup.·InvL (GroupStr.isGroup grp) = SQ.elimProp (λ _ → squash/ _ _) λ x → cong [_] (·InvL x)
quotientRec : (R : Graph {ℓ' = ℓ} ⟨ G ⟩) {H : Group ℓ} (f : GroupHom G H) → ((r : total R) → fst f (src R r) ≡ fst f (tgt R r)) → GroupHom (quotient (freeCongruenceCongruence R)) H
quotientRec R {H} f rel = f/ , igh
where
isSetH : isSet ⟨ H ⟩
isSetH = snd H .GroupStr.is-set
R* = freeCongruenceCongruence R
G/R* = quotient R*
fR* : {x y : ⟨ G ⟩} (r : fst R* x y) → fst f x ≡ fst f y
fR* (fcBase r) = rel r
fR* fcRefl = refl
fR* (fcTrans r s) = fR* r ∙ fR* s
fR* (fcSym r) = sym (fR* r)
fR* (fcProd r s) = f .snd .IsGroupHom.pres· _ _ ∙ cong₂ (snd H .GroupStr._·_) (fR* r) (fR* s) ∙ sym (f .snd .IsGroupHom.pres· _ _)
f/ : ⟨ quotient R* ⟩ → ⟨ H ⟩
f/ x = SQ.rec isSetH (fst f) (λ _ _ → fR*) x
open IsGroupHom
igh : IsGroupHom (snd G/R*) f/ (snd H)
pres· igh x y = SQ.elimProp2
{P = λ x y → f/ (snd G/R* .GroupStr._·_ x y) ≡ snd H .GroupStr._·_ (f/ x) (f/ y)}
(λ _ _ → isSetH _ _)
(snd f .pres·)
x y
pres1 igh = snd f .pres1
presinv igh x = SQ.elimProp
{P = λ x → f/ (snd G/R* .GroupStr.inv x) ≡ snd H .GroupStr.inv (f/ x)}
(λ x → isSetH _ _)
(snd f .presinv)
x
open import Cubical.HITs.FreeGroup as FG hiding (assoc)
Presentation : {ℓ : Level} → Type _
Presentation {ℓ} = TypeWithStr ℓ (λ X → Graph {ℓ' = ℓ} (FreeGroup X))
_* : Presentation → Group ℓ
P * = freeGroupGroup ⟨ P ⟩
∣_∣ : {ℓ : Level} → Presentation {ℓ} → Group ℓ
∣ P ∣ = quotient (P *) (freeCongruenceCongruence (P *) (str P))
module _ {ℓ : Level} (P : Presentation {ℓ}) where
open Span (str P)
1P = GroupStr.1g (str ∣ P ∣)
_·P_ = GroupStr._·_ (str ∣ P ∣)
invP = GroupStr.inv (str ∣ P ∣)
Rel = total
data 1Delooping : Type ℓ where
⋆ : 1Delooping
gen : (a : ⟨ P ⟩) → ⋆ ≡ ⋆
1Delooping-elim :
(A : 1Delooping → Type ℓ)
(Apt : A ⋆) →
((a : ⟨ P ⟩) → PathP (λ i → cong A (gen a) i) Apt Apt) →
(x : 1Delooping) → A x
1Delooping-elim A Apt Agen ⋆ = Apt
1Delooping-elim A Apt Agen (gen a i) = Agen a i
postulate
isGroupoid1Delooping : isGroupoid 1Delooping
Ω1Delooping : Group ℓ
Ω1Delooping = makeGroup {G = ⋆ ≡ ⋆} refl _∙_ sym (isGroupoid1Delooping ⋆ ⋆) assoc (λ p → sym (rUnit p)) (λ p → sym (lUnit p)) rCancel lCancel
gen* : GroupHom (P *) Ω1Delooping
gen* = FG.rec gen
path : (u : ⟨ P * ⟩) → ⋆ ≡ ⋆
path = fst gen*
data Delooping : Type ℓ where
inj : 1Delooping → Delooping
rel : (r : Rel) → cong inj (path (src r)) ≡ cong inj (path (tgt r))
gpd : isGroupoid Delooping
pathD :
(A : Delooping → Type ℓ)
(Apt : A (inj ⋆))
(Agen : (a : ⟨ P ⟩) → PathP (λ i → A (inj (gen a i))) Apt Apt) →
(u : ⟨ P * ⟩) → PathP (λ i → A (inj (path u i))) Apt Apt
pathD A Apt Agen u = cong (1Delooping-elim (λ x → A (inj x)) Apt Agen) (path u)
Delooping-elim :
(A : Delooping → Type ℓ)
(Apt : A (inj ⋆))
(Agen : (a : ⟨ P ⟩) → PathP (λ i → A (inj (gen a i))) Apt Apt)
(Arel : (r : Rel) → PathP (λ i → PathP (λ j → A (rel r i j)) Apt Apt) (pathD A Apt Agen (src r)) (pathD A Apt Agen (tgt r))) →
((x : Delooping) → isGroupoid (A x)) → (x : Delooping) → A x
Delooping-elim A Apt Agen Arel Agpd (inj x) = 1Delooping-elim (λ x → A (inj x)) Apt Agen x
Delooping-elim A Apt Agen Arel Agpd (rel r i j) = Arel r i j
Delooping-elim A Apt Agen Arel Agpd (gpd x y p q P Q i j k) = isOfHLevel→isOfHLevelDep 3 Agpd (f x) (f y) (cong f p) (cong f q) (cong (cong f) P) (cong (cong f) Q) (gpd x y p q P Q) i j k
where
f = Delooping-elim A Apt Agen Arel Agpd
open import Cubical.HITs.EilenbergMacLane1 as EM
theorem : Delooping ≃ EM₁ ∣ P ∣
theorem = isoToEquiv e
where
f1 : 1Delooping → EM₁ ∣ P ∣
f1 ⋆ = embase
f1 (gen a i) = emloop [ η a ] i
pathToEM : (u : ⟨ P * ⟩) → cong f1 (path u) ≡ emloop [ u ]
pathToEM = FG.elimProp
{B = λ u → cong f1 (path u) ≡ emloop [ u ]}
(λ _ → emsquash _ _ _ _)
(λ a → refl)
(λ u v p q →
cong f1 (path u ∙ path v) ≡⟨ cong-∙ f1 (path u) (path v) ⟩
cong f1 (path u) ∙ cong f1 (path v) ≡⟨ cong₂ _∙_ p q ⟩
emloop [ u ] ∙ emloop [ v ] ≡⟨ sym (emloop-comp ∣ P ∣ [ u ] [ v ]) ⟩
emloop (GroupStr._·_ (snd ∣ P ∣) [ u ] [ v ]) ≡⟨ refl ⟩
emloop [ u · v ] ∎
)
(sym (emloop-1g ∣ P ∣))
(λ u p →
cong f1 (sym (path u)) ≡⟨ refl ⟩
sym (cong f1 (path u)) ≡⟨ cong sym p ⟩
sym (emloop [ u ]) ≡⟨ sym (emloop-sym ∣ P ∣ [ u ]) ⟩
emloop [ inv u ] ∎
)
f1rel : (r : Rel) → cong f1 (path (src r)) ≡ cong f1 (path (tgt r))
f1rel r = pathToEM (src r) ∙ cong emloop (eq/ _ _ (fcBase r)) ∙ sym (pathToEM (tgt r))
f : Delooping → EM₁ ∣ P ∣
f (inj x) = f1 x
f (rel r i j) = f1rel r i j
f (gpd x y p q P Q i j k) = emsquash (f x) (f y) (cong f p) (cong f q) (λ i j → f (P i j)) (λ i j → f (Q i j)) i j k
Ωgroup : {ℓ : Level} (A : Pointed ℓ) → isGroupoid ⟨ A ⟩ → Group ℓ
Ωgroup A Gpd = makeGroup {G = pt A ≡ pt A} refl (λ p q → p ∙ q) sym (Gpd _ _) GL.assoc (λ p → sym (GL.rUnit p)) (λ p → sym (GL.lUnit p)) GL.rCancel GL.lCancel
ΩBP : Group ℓ
ΩBP = Ωgroup (Delooping , inj ⋆) gpd
injGrp : GroupHom Ω1Delooping ΩBP
injGrp = (cong inj) , igh
where
open IsGroupHom
igh : IsGroupHom (snd Ω1Delooping) (cong inj) (snd ΩBP)
pres· igh = cong-∙ inj
pres1 igh = refl
presinv igh p = refl
loopHom : GroupHom (∣ P ∣) ΩBP
loopHom = quotientRec _ (str P) (compGroupHom gen* injGrp) rel
loop : ⟨ ∣ P ∣ ⟩ → ⟨ ΩBP ⟩
loop = fst loopHom
loop· : (u v : ⟨ ∣ P ∣ ⟩) → loop (u ·P v) ≡ loop u ∙ loop v
loop· = IsGroupHom.pres· (snd loopHom)
g : EM₁ ∣ P ∣ → Delooping
g = EM.elimGroupoid
∣ P ∣
(λ _ → gpd)
(inj ⋆)
(λ u → loop u)
(λ u v → toPathP (lem u v))
where
lem : (u v : ⟨ ∣ P ∣ ⟩) → transport (λ i → loop u i ≡ loop (u ·P v) i) refl ≡ loop v
lem u v =
transport (λ i → loop u i ≡ loop (u ·P v) i) refl ≡⟨ subst2≡ (loop u) (loop (u ·P v)) refl ⟩
sym (loop u) ∙ refl ∙ loop (u ·P v) ≡⟨ cong (λ p → sym (loop u) ∙ p) (sym (lUnit _)) ⟩
sym (loop u) ∙ loop (u ·P v) ≡⟨ cong (λ p → sym (loop u) ∙ p) (loop· u v) ⟩
sym (loop u) ∙ (loop u ∙ loop v) ≡⟨ assoc _ _ _ ⟩
(sym (loop u) ∙ loop u) ∙ loop v ≡⟨ cong (λ p → p ∙ loop v) (lCancel (loop u)) ⟩
refl ∙ loop v ≡⟨ sym (lUnit (loop v)) ⟩
loop v ∎
fg : (x : EM₁ ∣ P ∣) → f (g x) ≡ x
fg = EM.elimSet ∣ P ∣ (λ x → emsquash (f (g x)) x) refl λ x → toPathP (lem x)
where
lem' : (x : ⟨ ∣ P ∣ ⟩) → cong f (loop x) ≡ emloop x
lem' = SQ.elimProp (λ _ → emsquash _ _ _ _) word
where
word : (u : ⟨ P * ⟩) → cong f (loop [ u ]) ≡ emloop [ u ]
word = FG.elimProp
(λ _ → emsquash _ _ _ _)
(λ _ → refl)
(λ u v p q →
cong f (loop [ u · v ]) ≡⟨ refl ⟩
cong f (loop ([ u ] ·P [ v ])) ≡⟨ cong (cong f) (loop· [ u ] [ v ]) ⟩
cong f (loop [ u ] ∙ loop [ v ]) ≡⟨ cong-∙ f (loop [ u ]) (loop [ v ]) ⟩
cong f (loop [ u ]) ∙ cong f (loop [ v ]) ≡⟨ cong₂ _∙_ p q ⟩
emloop [ u ] ∙ emloop [ v ] ≡⟨ sym (emloop-comp _ [ u ] [ v ]) ⟩
emloop ([ u ] ·P [ v ]) ≡⟨ refl ⟩
emloop [ u · v ] ∎
)
(sym (emloop-1g ∣ P ∣))
(λ u p →
cong f (loop [ inv u ]) ≡⟨ refl ⟩
cong f (loop (invP [ u ])) ≡⟨ refl ⟩
cong f (sym (loop [ u ])) ≡⟨ refl ⟩
sym (cong f (loop [ u ])) ≡⟨ cong sym p ⟩
sym (emloop [ u ]) ≡⟨ sym (emloop-sym _ [ u ]) ⟩
emloop (invP [ u ]) ≡⟨ refl ⟩
emloop [ inv u ] ∎
)
lem : (x : ⟨ ∣ P ∣ ⟩) → subst2 _≡_ (cong (f ∘ g) (emloop x)) (emloop x) refl ≡ refl
lem x =
subst2 _≡_ (cong (f ∘ g) (emloop x)) (emloop x) refl ≡⟨ subst2≡Refl (cong (f ∘ g) (emloop x)) (emloop x) ⟩
sym (cong (f ∘ g) (emloop x)) ∙ emloop x ≡⟨ refl ⟩
sym (cong f (cong g (emloop x))) ∙ emloop x ≡⟨ refl ⟩
sym (cong f (loop x)) ∙ emloop x ≡⟨ cong₂ _∙_ (cong sym (lem' x)) refl ⟩
sym (emloop x) ∙ emloop x ≡⟨ lCancel _ ⟩
refl ∎
gf : (x : Delooping) → g (f x) ≡ x
gf = Delooping-elim (λ x → g (f x) ≡ x) refl gf-gen gf-rel (λ x → isSet→isGroupoid (gpd (g (f x)) x))
where
gf-gen' : (a : ⟨ P ⟩) → cong g (emloop [ η a ]) ≡ cong inj (gen a)
gf-gen' a =
cong g (emloop [ η a ]) ≡⟨ refl ⟩
loop [ η a ] ≡⟨ refl ⟩
cong inj (gen a) ∎
gf-gen : (a : ⟨ P ⟩) → PathP (λ i → g (f1 (gen a i)) ≡ inj (gen a i)) refl refl
gf-gen a i j = gf-gen' a j i
gf-rel' : (r : Rel) → Cube
(pathD (λ x → g (f x) ≡ x) refl gf-gen (src r))
(pathD (λ x → g (f x) ≡ x) refl gf-gen (tgt r))
refl
refl
(cong (cong g) (f1rel r))
(rel r)
gf-rel' r = isGroupoid→isGroupoid' gpd _ _ _ _ _ _
gf-rel : (r : Rel) →
PathP (λ i → PathP (λ j → g (f1rel r i j) ≡ rel r i j) refl refl)
(pathD (λ x → g (f x) ≡ x) refl gf-gen (src r))
(pathD (λ x → g (f x) ≡ x) refl gf-gen (tgt r))
gf-rel r = gf-rel' r
open Iso
e : Iso Delooping (EM₁ ∣ P ∣)
fun e = f
Iso.inv e = g
rightInv e = fg
leftInv e = gf