open import 1Lab.Reflection.Induction
open import 1Lab.Prelude

open import Algebra.Group.Cat.Base
open import Algebra.Group.Homotopy
open import Algebra.Group.Ab
open import Algebra.Group

open import Cat.Base

open import Data.Set.Truncation

open import Homotopy.Connectedness
open import Homotopy.Conjugation

module Homotopy.Space.Delooping where


Deloopingsπ

A natural question to ask, given that all pointed types have a fundamental group, is whether every group arises as the fundamental group of some type. The answer to this question is βyesβ, but in the annoying way that questions like these tend to be answered: Given any group we construct a type with We call the delooping of

module _ {β} (G : Group β) where
module G = Group-on (G .snd)
open G

  data Deloop : Type β where
base    : Deloop
path    : β G β β base β‘ base
path-sq : (x y : β G β) β Square refl (path x) (path (x β y)) (path y)
squash  : is-groupoid Deloop

Deloopβ : Typeβ β
Deloopβ = Deloop , base

  private instance
H-Level-Deloop : β {n} β H-Level Deloop (3 + n)
H-Level-Deloop = basic-instance 3 squash


The delooping is constructed as a higher inductive type. We have a generic base point, and a constructor expressing that Deloop is a groupoid; Since it is a groupoid, it has a set of loops point β‘ point: this is necessary, since otherwise we would not be able to prove that We then have the βinterestingβ higher constructors: path lets us turn any element of to a path point β‘ point, and path-sq expresses that path is a group homomorphism. More specifically, path-sq fills the square below:

Using the uniqueness result for double composition, we derive that path is a homomorphism in the traditional sense:

  abstract
path-β : β x y β path (x β y) β‘ path x β path y
path-β x y i j =
Β·Β·-unique refl (path x) (path y)
(path (x β y)    , path-sq x y)
(path x β path y , β-filler _ _)
i .fst j

And the standard argument shows that path, being a group homomorphism, preserves the group identity.
    path-unit : path unit β‘ refl
path-unit =
path unit                               β‘β¨ sym (β-idr _) β©β‘
path unit β β refl β                    β‘Λβ¨ apΒ‘ (β-invr _)  β©β‘Λ
path unit β path unit β sym (path unit) β‘β¨ β-assoc _ _ _ β apβ _β_ (sym (path-β _ _)) refl β©β‘
path β unit β unit β β sym (path unit)  β‘β¨ ap! G.idr β©β‘
path unit β sym (path unit)             β‘β¨ β-invr _  β©β‘
refl                                    β


We define an elimination principle for Deloop, which has the following monstruous type since it works for mapping into arbitrary groupoids. As usual, if weβre mapping into a family of types thatβs more truncated (i.e.Β a family of sets or propositions), some of the higher cases become automatic.

  Deloop-elim
: β {β'} (P : Deloop β Type β')
β (β x β is-groupoid (P x))
β (p : P base)
β (ploop : β x β PathP (Ξ» i β P (path x i)) p p)
β ( β x y
β SquareP (Ξ» i j β P (path-sq x y i j))
(Ξ» _ β p) (ploop x) (ploop (x β y)) (ploop y))
β β x β P x

  unquoteDef Deloop-elim = make-elim-with (default-elim-visible into 3)
Deloop-elim (quote Deloop)

unquoteDecl Deloop-elim-set = make-elim-with (default-elim-visible into 2)
Deloop-elim-set (quote Deloop)

unquoteDecl Deloop-elim-prop = make-elim-with (default-elim-visible into 1)
Deloop-elim-prop (quote Deloop)


We can then proceed to characterise the type point β‘ x by an encode-decode argument. We define a family Code, where the fibre over base is definitionally G; Then we exhibit inverse equivalences base β‘ x β Code x and Code x β base β‘ x, which fit together to establish G β‘ (base β‘ base).

Weβll want to define the family Code by induction on Deloop. First, since we have to map into a groupoid, weβll map into the type rather than This takes care of the truncation constructor (which is hidden from the page since it is entirely formulaic): letβs tackle the rest in order. We can also handle the base case, since Code base = G was already a part of our specification.

  Code : Deloop β Set β
Code = go module Code where
open is-iso

base-case : Set β
β£ base-case β£    = β G β
base-case .is-tr = hlevel 2


To handle the path case, weβll have to produce, given an element an equivalence by univalence, we can then lift this equivalence to a path which we can use as the path-case. While there might be many maps one is canonical: the Yoneda embedding map, sending to

    path-case : β G β β base-case β‘ base-case
path-case x = n-ua eqv module path-case where
remβ : is-iso (_β x)
remβ .inv = _β x β»ΒΉ
remβ .rinv x = cancelr inversel
remβ .linv x = cancelr inverser

eqv : β G β β β G β
eqv .fst = _
eqv .snd = is-isoβis-equiv remβ

open path-case


Finally, we can satisfy the coherence case path-sq by an algebraic calculation on paths:

    coh : β x y β Square refl (path-case x) (path-case (x β y)) (path-case y)
coh x y = n-Type-square $transport (sym Squareβ‘double-composite-path)$
ua (eqv x) β ua (eqv y) β‘Λβ¨ uaβ β©β‘Λ
ua (eqv x βe eqv y)     β‘β¨ ap ua (Ξ£-prop-path! (funext Ξ» _ β sym associative)) β©β‘
ua (eqv (x β y))        β

    go : Deloop β Set β
go base = base-case
go (path x i) = path-case x i
go (path-sq x y i j) = coh x y i j
go (squash x y p q Ξ± Ξ² i j k) =
n-Type-is-hlevel 2 (Code x) (Code y)
(Ξ» i β Code (p i))     (Ξ» i β Code (q i))
(Ξ» i j β Code (Ξ± i j)) (Ξ» i j β Code (Ξ² i j))
i j k


We can then define the encoding and decoding functions. The encoding function encode is given by lifting a path from Deloop to Code. For decoding, we do induction on Deloop with Code x .fst β base β‘ x as the motive.

  opaque
encode : β x β base β‘ x β Code Κ» x
encode x p = subst (Code Κ»_) p unit

decode : β x β Code Κ» x β base β‘ x
decode = go where
coh : β x β PathP (Ξ» i β Code Κ» path x i β base β‘ path x i) path path
coh x i c j = hcomp (β i β¨ β j) Ξ» where
k (k = i0) β path (ua-unglue (Code.path-case.eqv x) i c) j
k (i = i0) β path-sq c x (~ k) j
k (i = i1) β path c j
k (j = i0) β base
k (j = i1) β path x (i β¨ ~ k)

go : β x β Code Κ» x β base β‘ x
go base c = path c
go (path x i) c = coh x i c
go (path-sq x y i j) = is-setβsquarep
(Ξ» i j β fun-is-hlevel {A = Code Κ» path-sq x y i j} 2 (Deloop.squash base (path-sq x y i j)) )
(Ξ» i β path) (coh x) (coh (x β y)) (coh y) i j
go (squash x y p q Ξ± Ξ² i j k) =
is-hlevelβis-hlevel-dep {B = Ξ» x β Code Κ» x β base β‘ x} 2 (Ξ» x β hlevel 3)
(go x) (go y) (Ξ» i β go (p i)) (Ξ» i β go (q i))
(Ξ» i j β go (Ξ± i j)) (Ξ» i j β go (Ξ² i j)) (squash x y p q Ξ± Ξ²) i j k


Proving that these are inverses finishes the proof. For one direction, we use path induction to reduce to the case decode base (encode base refl) β‘ refl; A quick argument tells us that encode base refl is the group identity, and since path is a group homomorphism, we have path unit = refl, as required.

  opaque
unfolding encode

encodeβdecode : β {x} (p : base β‘ x) β decode x (encode x p) β‘ p
encodeβdecode p =
J (Ξ» y p β decode y (encode y p) β‘ p)
(ap path (transport-refl _) β path-unit)
p


In the other direction, we do induction on deloopings; Since the motive is a family of propositions, we can use Deloop-elim-prop instead of the full Deloop-elim, which reduces the goal to proving

    decodeβencode : β x (c : Code Κ» x) β encode x (decode x c) β‘ c
decodeβencode =
Deloop-elim-prop
(Ξ» x β (c : Code Κ» x) β encode x (decode x c) β‘ c)
(Ξ» x β Ξ -is-hlevel 1 Ξ» _ β Code x .is-tr _ _)
Ξ» c β transport-refl _ β G.idl


This completes the proof, and lets us establish that the fundamental group of Deloop is G, which is what we wanted.

  GβΞ©B : β G β β (base β‘ base)
GβΞ©B = IsoβEquiv (decode base , iso (encode base) encodeβdecode (decodeβencode base))

Gβ‘ΟβB : G β‘ Οβββ 0 (Deloop , base)
Gβ‘ΟβB = β«-Path
(total-hom (Ξ» x β inc (path x))
record { pres-β = Ξ» x y β ap β₯_β₯β.inc (path-β _ _) })
(β-is-equiv (GβΞ©B .snd) (β₯-β₯β-idempotent (squash base base)))


Since Deloop is a groupoid, each of its loop spaces is automatically a set, so we do not necessarily need the truncation when taking its fundamental group. This alternative construction is worth mentioning since it allows us to trade a proof that encode preserves multiplication for proofs that it also preserves the identity, inverses, differences, etc.

  encode-is-group-hom
: is-group-hom (ΟβGroupoid.on-Ξ© Deloopβ squash) (G .snd) (encode base)
encode-is-group-hom .is-group-hom.pres-β x y = eqv.injectiveβ (eqv.Ξ΅ _) $path (encode base x β encode base y) β‘β¨ path-β (encode base x) (encode base y) β©β‘ path (encode base x) β path (encode base y) β‘β¨ apβ _β_ (eqv.Ξ΅ _) (eqv.Ξ΅ _) β©β‘ x β y β where module eqv = Equiv GβΞ©B   module encode where open is-group-hom encode-is-group-hom public open Equiv (Equiv.inverse GβΞ©B) public instance H-Level-Deloop : β {n} {β} {G : Group β} β H-Level (Deloop G) (3 + n) H-Level-Deloop {n} = basic-instance 3 squash  For abelian groupsπ module _ {β} (G : Group β) (ab : is-commutative-group G) where open Group-on (G .snd) open is-group-hom opaque  If is an abelian group, then we can characterise the loop spaces of based at totally arbitrary points, rather than the above characterisation which only applies for the loop space at base. Our proof starts with the following immediate observation: multiplication in is commutative as well.  β-comm : (p q : Path (Deloop G) base base) β p β q β‘ q β p β-comm p q = encode.injective G (encode.pres-β G _ _ Β·Β· ab _ _ Β·Β· sym (encode.pres-β G _ _))  Weβll construct a function that computes the βwinding numberβ of a loop with arbitrary base.  winding : {x : Deloop G} β x β‘ x β β G β winding {x = x} = go x module windingβ± where   hl : (x : Deloop G) β is-set (x β‘ x β β G β) hl _ = hlevel 2 interleaved mutual go : (x : Deloop G) β x β‘ x β β G β coherence : Type _ [ i1 β¦ (Ξ» ._ β (x : β G β) β PathP (Ξ» i β path {G = G} x i β‘ path x i β β G β) (encode G base) (encode G base)) ] coh : outS coherence   deg : base β‘ base β β G β deg = encode G base go base loop = deg loop  If the loop is indeed based at the basepoint constructor, then we can appeal to the existing construction; Weβll abbreviate it as deg for this construction. Since our codomain is a set, the higher cases are both handled mechanically; We omit them from the page in the interest of parsimony. Weβre left with tackling the path case, which means constructing a term exhibiting the coherence below:  coherence = inS ( β b β PathP (Ξ» i β path b i β‘ path b i β β G β) deg deg)  This condition is a bit funky, since at first glance it looks like all we must do is equate deg with itself. However, weβre doing this over a non-trivial identification in the domain. By extensionality for dependent functions, the above is equivalent to showing that deg produces identical results given an element and loops fiting into a commutative square Since commutativity of the diagram above says precisely that is the conjugate of by we can reason about conjugation instead; And since weβve shown that this conjugation is just again. That finishes the construction:  abstract coh b = funext-dep Ξ» {xβ} {xβ} p β ap deg$ sym $xβ β‘Λβ¨ pathpβconj p β©β‘Λ conj (path b) xβ β‘β¨ conj-commutative (β-comm xβ (path b)) β©β‘ xβ β go (path x i) loop = coh x i loop   go (path-sq x y i j) = is-setβsquarep (Ξ» i j β hl (path-sq x y i j)) (Ξ» j β encode G base) (coh x) (coh (x β y)) (coh y) i j go (squash x y p q Ξ± Ξ² i j k) = is-hlevelβis-hlevel-dep 2 (Ξ» x β is-hlevel-suc 2 (hl x)) (go x) (go y) (Ξ» i β go (p i)) (Ξ» j β go (q j)) (Ξ» i j β go (Ξ± i j)) (Ξ» i j β go (Ξ² i j)) (squash x y p q Ξ± Ξ²) i j k {-# DISPLAY windingβ±.go x p = winding p #-}  We could go on to define the inverse to winding similar to how we constructed decode, but thereβs a trick: since being an equivalence is a proposition, if we want to show is an equivalence for arbitrary it suffices to do so for but weβve already shown thatβs an equivalence! A similar remark allows us to conclude that is a group homomorphism  opaque winding-is-equiv : β x β is-equiv (winding {x}) winding-is-equiv = Deloop-elim-prop G _ (Ξ» _ β hlevel 1)$

winding-is-group-hom : β x β
is-group-hom (ΟβGroupoid.on-Ξ© (Deloop G , x) (hlevel 3))
(G .snd) (winding {x})
winding-is-group-hom = Deloop-elim-prop G _ (Ξ» x β hlevel 1) Ξ» where
.pres-β x y β encode.pres-β G x y


We can then obtain a nice interface for working with winding.

  module winding {x} where
open Equiv (winding , winding-is-equiv x) public
open is-group-hom (winding-is-group-hom x) public

pathα΅ : (x : Deloop G) β β G β β x β‘ x
pathα΅ _ = winding.from

  -- Want: pathα΅ base β‘ path, definitionally
-- Have: pathα΅ base is a projection from some opaque record
-- Soln: Evil hack!
opaque
unfolding winding-is-equiv

winding-is-equiv-base : winding-is-equiv base β‘ Equiv.inverse (GβΞ©B G) .snd
winding-is-equiv-base = prop!

{-# REWRITE winding-is-equiv-base #-}

_ : pathα΅ base β‘ path
_ = refl -- MUST check!

pathα΅-sq : β (x : Deloop G) g h β Square refl (pathα΅ x g) (pathα΅ x (g β h)) (pathα΅ x h)
pathα΅-sq = Deloop-elim-prop G _ (Ξ» x β hlevel 1) Ξ» g h β path-sq g h

Deloop-is-connected : β {β} {G : Group β} β is-connectedβ (Deloop G , base)
Deloop-is-connected = Deloop-elim-prop _ _ (Ξ» _ β hlevel 1) (inc refl)