Quest 2 - is a Set

An overview of this quest :

  • We want to show that the higher loop spaces of are trivial

  • We note that it suffices to show that the loop space of is trivial, assuming the end result loopSpace base .

  • Show that the loop space of any set is trivial, hence it suffices to show that is a set

  • Show that looks like the sum of two disjoint copies of , and is a set; it then suffices to show the general result that the disjoint sum of two sets is a set.

  • To show that the disjoint sum of sets is a set we find ourselves trying to classify the path space of disjoint sums.

The bulk of the work will be to classify the path space of disjoint sums, and showing that it actually corresponds to the path space. This is the content of the last three parts.

Part 0 - loopSpace loopSpace

We are interested in knowing what the higher homotopy groups of might be. Whilst the data of the fundamental group π₁ is captured in loopSpace base, the data of π₂ would be captured in loopSpace (loopSpace base) refl; loops in loopSpace base based at refl. Points in the second loop space are paths h : refl refl, i.e. h would be a homotopy from the constant path to itself.

The second loop space contains an obvious point refl : refl refl (this is of course not the same “refl” as the one before), and we could define the next loop space to be loops in loopSpace (loopSpace base) refl based at refl (the one from loopSpace base that is).

The important conclusion we will arrive at in this quest is that the loop space of - which will correspond to the second loop space of (this is the conclusion of this entire arc) - is trivial, in the sense that it just consists of a point (up to paths) :

loopSpace (loopSpace S¹ base) refl ≡ loopSpace ℤ 0 ≡ ⊤

Intuitively this is because the only loop (up to a path) in from 0 to itself is refl, so loopSpace 0 is contractible - it looks just like the singleton space . This is more general : any two paths in are homotopic, which we formalise in the definition isSet.



The statement “any two paths in the space A are homotopic” is captured in the definition of isSet :

isSet : Type  Type
isSet A = (x y : A)  isProp (x  y)

In the above isProp captures the statement “any two points are (continuously) connected by a path” :

isProp : Type  Type
isProp A = (x y : A)  x  y

If a type satisfies isSet we say it is a set, and if it satisfies isProp we say it is a proposition.

Why the words "set" and "proposition"?

Intuitively a “set” is meant to be a bunch of disjoint points. However in homotopy type theory we consider points up to paths, and paths up to homotopy, hence a “set” is a bunch of disjoint blobs, where each blob is contractible to a point. In other words a “set” is a type where any circle (that lands in a blob) can be filled (hence the blob is contractible).

We will justify the use of the word “proposition” once we have introduced the propositional perspective on types, see trinitarianism and Part 5 - Using the Propositional Perspective.

All maps are continuous in HoTT

There is a subtlety in the definition isProp. Having isProp A is stronger than saying that the space A is path connected. Since A is equipped with a continuous map taking pairs x y : A to a path between them.

We will show in a later quest that isProp is empty despite being path connected.

We can justify “the loop space of a set is trivial” by showing that “if any two paths in a space A are homotopic then the loop space of A at any point in A looks like ”. So we show that

isSet→LoopSpace≡⊤ : {A : Type} (x : A)  isSet A  (x  x)  
isSet→LoopSpace≡⊤ = {!!}

Locate this in 1FundamentalGroup/Quest2.agda and try filling it in.

Hint 0

Imitating what we did with flipPath and flipIso reduce this to showing that for each x : A and h : isSet A we have

  • fun : x x

  • inv : x x

  • rightInv : section fun inv

  • leftInv : retract inv fun

Hint 1

There is only one possible map from x x to since is terminal (see trinitarianism).

To map out of one can do cases and see that you only need to map tt.

  • fun can just be p tt)

  • inv can be

    inv :   x  x
    inv tt = refl

Hint 2

For rightInv by casing on the point in there should be nothing much to show.

For leftInv we need to use our assumption that “any two paths are homotopic”.

rightInv : section (λ p  tt) inv
rightInv tt = refl

leftInv : retract (λ p  tt) inv
leftInv p = h x x refl p

The goal

We have therefore reduced our goal to showing that is a set, i.e. only has trivial paths in it, which will tell us that the second loop (and in fact any higher loop space) of is trivial.

Part 1 - as a disjoint sum

As a first step, we note that actually looks like two disjoint copies of , i.e. we have

ℤ≡ℕ⊔ℕ :     

where we have the definition of the disjoint sum of two spaces as follows

data _⊔_ (A B : Type) : Type where

  inl : A  A  B
  inr : B  A  B

It says there are two ways of making points in the space, taking them from A and taking them from B. Try proving in 1FundamentalGroup/Quest2.agda.


As in defining flipPath in quest 0 we first make an isomorphism and then convert it to a path/proof of equality. To make the isomorphism note that the definition of is already as “two copies of ”, as described in quest 1.

If you have made the function and inverse appropriately, you should only need constant paths in the proofs that they satisfy section and retract respectively.

ℤ≡ℕ⊔ℕ :     
ℤ≡ℕ⊔ℕ = isoToPath (iso fun inv rightInv leftInv) where

fun :     
fun (pos n) = inl n
fun (negsuc n) = inr n

inv :     
inv (inl n) = pos n
inv (inr n) = negsuc n

rightInv : section fun inv
rightInv (inl n) = refl
rightInv (inr n) = refl

leftInv : retract fun inv
leftInv (pos n) = refl
leftInv (negsuc n) = refl

We want to show that is a set, by using the path ℤ≡ℕ⊔ℕ. Intuitively if is a set then two disjoint copies of it should also be a set, (think about filling circles on the disjoint sum). Thus we can break down our goal into two :

Goal 1 : is a set

isSetℕ : isSet 
isSetℕ = {!!}

Goal 2

If A and B are both sets then A B is also a set.

Goal 1 will be handled in a side quest. We focus on Goal 2 from now on.

Part 2 - Disjoint Sum of Sets is a Set

Try formulating (but not proving) the result isSet⊔, which should say “if spaces A and B are both sets then so is their disjoint sum A B”. This should be done in 1FundamentalGroup/Quest2.agda where indicated.

isSet⊔ : {A B : Type} → isSet A → isSet B → isSet (A ⊔ B)
isSet⊔ = {!!}

Without proving this, we can use this to show isSet (ℕ ℕ) using isSetℕ : isSet , which will be shown in a side quest. Then using either pathToFun or endPt you can show isSet from isSet (ℕ ℕ), using the path from to we made earlier. Try to set up everything described in this paragraph where indicated in 1FundamentalGroup/Quest2.agda.

Hint : The statement
isSetℤ : isSet 

Hint : following along paths

To use pathToFun you must figure out what path you are following and what point you are following the path along.

To use endPt you must figure out what bundle you are making, what the path in the base space is, and what point you are starting at in the first fiber.

Partial solutions

The point you need to follow in either case is the point in the space isSet (ℕ ℕ) :

isSetℤ : isSet 
isSetℤ = pathToFun {!!} (isSet⊔ isSetℕ isSetℕ)

isSetℤ' : isSet 
isSetℤ' = endPt {!!} {!!} (isSet⊔ isSetℕ isSetℕ)

isSetℤ : isSet 
isSetℤ = pathToFun (cong isSet (sym ℤ≡ℕ⊔ℕ)) (isSet⊔ isSetℕ isSetℕ)

isSetℤ' : isSet 
isSetℤ' = endPt (λ A  isSet A) (sym ℤ≡ℕ⊔ℕ) (isSet⊔ isSetℕ isSetℕ)

Refining issues

If you tried refining using endPt you may have been given 2 holes instead of 3. This is because agda had too many possible options when trying to match up the output of endPt and the goal. To add an extra hole simply add a ? afterwards and reload.

Once this is complete we can go back and work on isSet⊔.

Part 3 - Path Space of Disjoint Sums


  • Locate your formulation of isSet⊔.

  • We assume hA : isSet A, hB : isSet B, and points x y : A B. Currently our code looks like

    isSet⊔ : {A B : Type}  isSet A  isSet B  isSet (A  B)
    isSet⊔ hA hB x y = {!!}
  • Check the goal. It should be asking for a point in the space isProp (x y).

    We need to consider how to get information on the path space of A B when our hypotheses are about the path spaces of A and B respectively. We could try to case on x and y.

  • If x and y are “both from A”, i.e. of the form inl ax and inl ay for ax ay : A, then we need to find a point in isProp (inl ax inl ay). This should be due to hA, which gives us hA ax ay : isProp (ax ay). So somehow we need to identify the path spaces inl ax inl ay and ax ay (try to formalize this, though we are not expecting a solution here).

  • If x and y are of the forms inl ax and inr by respectively for ax : A and by : B then intuitively the space inl ax inr bx should be empty, since the sum is disjoint (again we are not expecting a solution here).

  • The other two cases are similar.

The conclusion is that we need some kind of classification of the path space of disjoint sums.

Classifying the Path Space of Disjoint Sums

Path space of disjoint sums

A path in the the disjoint sum should just be a path in one of the two parts.

This says points from A cannot be confused with points from B or points in A that they were not already path connected to.

For now we leave isSet⊔ alone and define a function ⊔NoConfusion that takes two points in A B and returns a space, which is meant to represent the path space in each case, as described in our motivation above. Try to formulate (but not fill in) this where indicated in Quest2.agda. It should look like:

⊔NoConfusion : {A B : Type}  A  B  A  B  Type
⊔NoConfusion = {!!}

Assume points x and y in the disjoint sum and try to case on them. There should be four cases.

  • When both points are from A, i.e. they are inl ax and inl ay, then we should give the space ax ay, which we expect to be isomorphic to inl ax inl ay.

  • (Two cases) When each is from a different space we expect the path space between them to be empty, so we should give .

  • If both are from B then we should imitate what we did in the first case

⊔NoConfusion : A  B  A  B  Type
⊔NoConfusion (inl x) (inl y) = x  y -- Path A x y
⊔NoConfusion (inl x) (inr y) = 
⊔NoConfusion (inr x) (inl y) = 
⊔NoConfusion (inr x) (inr y) = x  y -- Path B x y

Using the Classification

Now we have two of goals :

  • Path≡⊔NoConfusion : We need to show that for each x y : A B the path space looks like our classification, i.e. that (x y) (⊔NoConfusion x y)

  • isSet⊔NoConfusion : For isSet⊔, given hA : isProp A, hB : isProp B and x y : A B we needed to show isProp (x y). Hence we want to show that under the same assumptions isProp (⊔NoConfusion x y).

Formalise (but don’t prove) both of these where indicated in 1FundamentalGroup/Quest2.agda. They should look like

Path≡⊔NoConfusion : (x y : A  B)  (x  y)  ⊔NoConfusion x y
Path≡⊔NoConfusion = {!!}

isSet⊔NoConfusion : isSet A  isSet B  (x y : A  B)  isProp (⊔NoConfusion x y)
isSet⊔NoConfusion = {!!}


If you are tired of writing {A B : Type} each time you can stick

    A B : Type

at the beginning of your agda file, and it will assume A and B implicitely whenever they are mentioned. Make sure it is indented correctly.

Without showing either of these new definitions, try using them to complete isSet⊔.


We can use pathToFun or endPt to follow how a point of “isProp applied to ⊔NoConfusion” changes into a point of “isProp on the path space x y”.

Partial solutions
isSet⊔ : {A B : Type}  isSet A  isSet B  isSet (A  B)
isSet⊔ hA hB x y = pathToFun {!!} (isSet⊔NoConfusion hA hB x y)

isSet⊔' : {A B : Type}  isSet A  isSet B  isSet (A  B)
isSet⊔' hA hB x y = endPt {!!} {!!} (isSet⊔NoConfusion hA hB x y)

isSet⊔ : {A B : Type}  isSet A  isSet B  isSet (A  B)
isSet⊔ hA hB x y = pathToFun (cong isProp (sym (Path≡⊔NoConfusion x y)))
                     (isSet⊔NoConfusion hA hB x y)

isSet⊔' : {A B : Type}  isSet A  isSet B  isSet (A  B)
isSet⊔' hA hB x y = endPt (λ A  isProp A) (sym (Path≡⊔NoConfusion x y))
                     (isSet⊔NoConfusion hA hB x y)

Proving isSet⊔NoConfusion

We will now show that ⊔NoConfusion “is a set”. Locate your definition of isSet⊔NoConfusion and try proving it.


We need to case on the points in A B.

  • If they are both “from A” then we need to show that the path spaces in A are propositions.

  • (2 cases) If they are from different spaces then we must show that the path spaces in are propositions.

  • If they are both “from B” then it is similar to the first case.

Part 4 - Proving Path≡⊔NoConfusion

It suffices to make an isomorphism

Replicate our proof of flipPath in quest 0, it suffices to show an isomorphism instead of an equality. Make this precise in 1FundamentalGroup/Quest2.


So that you can follow, we will make a lemma (you don’t have to) :

Path≅⊔NoConfusion : (x y : A  B)  (x  y)  ⊔NoConfusion x y
Path≅⊔NoConfusion = {!!}

To prove the isomorphism (for each arbitrary x and y) we need four things, which we can extract as local definitions / lemmas using where.

fun : (x y : A  B)  (x  y)  ⊔NoConfusion x y
fun x y = {!!}

inv : (x y : A  B)  ⊔NoConfusion x y  x  y
inv x y = {!!}

rightInv : (x y : A  B)  section (fun x y) (inv x y)
rightInv {A} {B} = {!!}

leftInv : (x y : A  B)  retract (fun x y) (inv x y)
leftInv = {!!}


First try defining inv : (x y : A B) ⊔NoConfusion x y x y.

Hint 0

Check the goal. You can assume points x y : A B and a point h : ⊔NoConfusion x y. If you case on x and y you might find there are fewer cases than you need. This is because ⊔NoConfusion (inl ax) (inr by) was defined to be empty, so agda automatically removes the case.

Hint 1

In the case that both points are from x we need to show that given a proof p : ax ay we get a proof of inl ax inr ay. We already have the result that if two points are equal then their images under a function are equal.

inv : (x y : A  B)  ⊔NoConfusion x y  x  y
inv (inl x) (inl y) p = cong inl p
inv (inr x) (inr y) p = cong inr p

Attempting fun

We try to define the map forward, which we called fun. If we assume and case on x and y in the disjoint sum then

  • When x and y are both from A then they will be inl ax and inl ay, so checking the goal we should be required to give a point in inl x inl y x y. Reading this carelessly one could call this “inl is injective”.

  • When x and y are from different spaces then checking the goal, we should be required to give a point in inl ax inr by . This says there are no paths between the disjoint parts.

  • The last case is similar to the first.

We can extract the second case as a lemma :

disjoint : (a : A) (b : B)  inl a  inr b  
disjoint a b p = {!!}

which we can prove by constructing a subsingleton bundle over A B, just like we did to prove that true false is empty, in the side quest. In fact this is a generalisation of that result, and the proof also generalises.


We make a bundle over the disjoint union with the starting fiber as and the ending fiber as .

disjoint : (a : A) (b : B)  inl a  inr b  
disjoint a b p = endPt bundle p tt where

  bundle : A  B  Type
  bundle (inl a) = 
  bundle (inr b) = 

The other case is quite problematic. This is what we want to show

inlInj : (x y : A) → (inl {A} {B} x ≡ inl y) → x ≡ y
inlInj x y p = {!!}

Here are the problems:

  • If we had a map backwards that cancelled inl we would be done, but in general this doesn’t exist. For example, if A were empty and B had a point then we cannot expect to have a map A B A.

  • There is nothing to induct on : we have no information about x y : A. More importantly :


    We don’t know how to induct on paths.

    Specifically we don’t yet know how to map out of a path space in general.

To find out how to induct on paths, complete quest 4 in trinitarianism, and return to this quest with a completely new perspective.

Part 5 - Using the Propositional Perspective

After learning about the propositional perspective on equality, we can review some of the things we showed in a new light :

  • a b can be read as a is not equal to b since assuming a proof that a is equal to b we have a point in the empty space.

  • In showing an isomorphism between spaces we must show that two functions satisfy fun (inv x) x for each x in the domain. This can now be read as fun composed with inv is equal to the identity on points.

  • isoToPath says that if two spaces are isomorphic then they are equal.

  • endPt (subst for substitute in the library) takes a bundle and a proof that x y in the base space and substitutes x for y, hence replacing a point in the fiber of x with a point in the fiber of y.

  • cong : (f : A B) (p : x y) f x f y says that if two points are equal then their images are equal.

  • true is not equal to false

  • refl is not equal to loop

  • flipPath : Bool Bool is a non-trivial equality between Bool and itself.

  • inl is injective (we still have not shown this yet).

  • The objective of this whole arc is to show that the fundamental group of the circle is equal to .

  • isProp says there is at most one point in the space; at most one proof of the proposition. Classically propositions are meant to only have a single proof (“proof irrelevance”), because for propositions A and B, having implications A B and B A is enough to show A B.

  • isSet says between any two points there is at most one path between them, i.e. “there is only refl”, i.e. the space is disjoint.

We shall apply this perspective to the problem at hand.


Now that we know how to induct on paths, we need to pick a path to induct on. Continuing with trying to show that inl is injective we will notice that path induction does not actually work here, since we have

  • a start point ax : A

  • a variable end point ay : A

  • but the path is in the disjoint union inl ax inl ay not a path in A

We instead take a step back and look at fun itself. (You can now abandon inlInj if you like, this will become a corollary of the classification.) We also remove the cases so that we are back to just having

fun : (x y : A  B)  (x  y)  ⊔NoConfusion x y
fun x y = {!!}

You might have noticed by now that we are in the perfect position to induct on paths in x y. Path induction - J - says that to make a function (x y : A B) (x y) ⊔NoConfusion x y, it suffices just to give a point in ⊔NoConfusion x x. Formalise the above (without showing ⊔NoConfusion x x yet) :

fun : (x y : A  B)  (x  y)  ⊔NoConfusion x y
fun x y = J (λ y' p  ⊔NoConfusion x y') {!!}

To prove ⊔NoConfusion x x it would be convenient to be able to case on x so we will extract it as a lemma. Once you extract and case on x this it should be quite easy to show.

⊔NoConfusionSelf : (x : A  B)  ⊔NoConfusion x x
⊔NoConfusionSelf (inl x) = refl
⊔NoConfusionSelf (inr x) = refl


Try to define rightInv : (x y : A B) section (fun x y) (inv x y).

Hint 0

It is a good idea to case on x and y in the space A B, since inv is the first to take these inputs in here, and inv was defined by casing on x and y. This should reduce us to just two cases, like when defining inv. We will just describe the case when they are both from A.

Hint 1

We can use J to reduce to the case of when the path is refl. (No proof of the refl case yet.)

rightInv : (x y : A  B)  section (fun x y) (inv x y)
rightInv {A} {B} (inl x) (inl y) p =
   J (λ y' p  fun {A} {B} (inl x) (inl y') (inv (inl x) (inl y') p)  p) {!!}

We added the implicit arguments {A} and {B} so we can actually access them here. The remaining hole is for showing that

fun (inl x) (inl x) (inv (inl x) (inl x) refl)  refl

Hint 2

It would help to make a chain of equalities. We defined inv (inl x) (inl x) refl to be refl, so we only need to show that

fun (inl x) (inl x) refl  refl

Since fun was defined using J we need to know how J computes when it is fed refl. We described this before, it is called JRefl.

rightInv : (x y : A  B)  section (fun x y) (inv x y)
rightInv {A} {B} (inl x) (inl y) p = J (λ y' p  fun {A} {B} (inl x) (inl y') (inv (inl x) (inl y') p)  p)
                       fun {A} {B} (inl x) (inl x) refl
                     ≡⟨ JRefl {x = inl x} ((λ y' p  ⊔NoConfusion {A} {B} (inl x) y')) _ 
                     -- uses how J computes on refl
                     ) p
rightInv {A} {B} (inr x) (inr y) p = {!!}


Try to define leftInv.

Hint 0

We do this but each part of this proof will be relevant anywayuse J since fun “happens first”. This should reduce the problem to showing

inv x x (fun x x refl) ≡ refl

leftInv : (x y : A  B)  retract (fun x y) (inv x y)
leftInv x y = J (λ y' p  inv x y' (fun x y' p)  p) {!!}

Hint 1

If you extract what is needed as a lemma you can case on the variable. Remember to use JRefl for the application of fun.

leftInv : (x y : A  B)  retract (fun x y) (inv x y)
leftInv x y = J (λ y' p  inv x y' (fun x y' p)  p)
                  (inv x x (fun x x refl))
                ≡⟨ cong (inv x x) (JRefl ((λ y' p  ⊔NoConfusion x y')) _) 
                  inv x x (⊔NoConfusionSelf x)
                ≡⟨ lem x 
                ) where

  lem : (x : A  B)  inv x x (⊔NoConfusionSelf x)  refl
  lem (inl x) = refl
  lem (inr x) = refl