Lecture 2-8: Sets and Higher Types

We saw in Lecture 2-X that paths in inductive types like Bool, and are equalities between elements. As a consequence, for any two elements x and y, the type of paths x ≡ y is always a proposition — specifically, the proposition that x equals y.

We call types with this property sets.

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

mvrnote: more intuition, uip, axiom k, etc

Basic Examples

We characterised the types of paths in , Bool and back in Lecture 2-X, and from these it is easy to show they are all sets.

isSet-⊤ : isSet 
-- Exercise: (Hint: `≡≃≡⊤`)
-- isSet-⊤ x y = isPropEquiv {!!} {!!}

isSet-Bool : isSet Bool
-- Exercise:
-- isSet-Bool x y = {!!}

isSet-ℕ : isSet 
-- Exercise:
-- isSet-ℕ x y = {!!}

The empty type is the set with no elements.

isSet-∅ : isSet 
-- Exercise:
-- isSet-∅ = {!!}

For , we will need a helper that relates paths in the two sides to the characterisation ≡⊎ from back in Lecture 2-X.

isProp-≡⊎ : {A B : Type}  isSet A  isSet B  (a b : A  B)  isProp (a ≡⊎ b)
-- Exercise:
-- isProp-≡⊎ sA sB a b = {!!}

isSet-⊎ : {A B : Type}  isSet A  isSet B  isSet (A  B)
-- Exercise:
-- isSet-⊎ pA pB = {!!}

Every proposition is a set. This may sound like an odd claim, especially if you are used to first-order logic where there is a strict separation between the two. In our setting, any proposition P is a set that has at most one element.

isProp→isSet : isProp A  isSet A
-- Exercise:
-- isProp→isSet pA x y = {!!}

Again, not all types are sets. The type should not be a set since we have a path loop that we know is not the same as refl.

¬isSet-S¹ : ¬ isSet 
-- Exercise:
-- ¬isSet-S¹ isSet = {!!}

The type Type is not a set either. If all paths in Type were equal, then not-Path would be equal to refl as a path Bool ≡ Bool, and this quickly leads to a contradiction.

¬isSet-Type : ¬ isSet Type
-- Exercise: (Hint: `true≢false`)
-- ¬isSet-Type s = {!!}

One way of thinking of isSet is that for any paths p : x ≡ y and q : x ≡ y there is a Square with shape

        refl
    y — — — — > y
    ^           ^            ^
  p |           | q        j |
    |           |            ∙ — >
    x — — — — > x              i
        refl

Of course, we can’t necessarily get some Square like this for any choice of corners x and y, we need the paths p and q to exist to begin with.

So, isSet is like isProp but one dimension higher. We can’t necessarily fill a path between any two points, but we can fill any Square:

isSet→Square : isSet A
   {a b c d : A}
   (r : a  c) (s : b  d)
   (t : a  b) (u : c  d)
   Square t u r s
-- Exercise: (Hint: `toPathP`)
-- isSet→Square sA r s t u = {!!}

Because being a set means that asking that a certain family of types is all propositions, isSet is a proposition about a type.

isProp-isSet : isProp (isSet A)
-- Exercise: (Use `isProp-Π`)
-- isProp-isSet = {!!}

Closure Properties

We can show a number of closure properties of sets like those for propositions and contractible types.

First, if A and B are sets, then A × B is a set, and for A → B it is sufficient for just B to be a set.

isSet-× : isSet A  isSet B  isSet (A × B)
-- Exercise:
-- isSet-× pA pB = {!!}

isSet-→ : isSet B  isSet (A  B)
-- Exercise:
-- isSet-→ pB = {!!}

Similarly to contractible types and propositions, any retract of a set is a set. This follows easily from the following general about fact about homotopies.

mvrnote: do we need a “functions are functors” section? mvrnote: what’s a good name for this? mvrnote: draw cube?

homotopy-conjugate : {f g : A  B}
   (H : (x : A)  (f x  g x))
   {a b : A}
   {r : a  b}
   f a  f b
   g a  g b
homotopy-conjugate {B = B} H {a = a} {b} p i = hcomp ( i) faces
  where 
    faces : (k : I)  Partial ( i  ~ k) B
    faces k (i = i0) = H a k
    faces k (i = i1) = H b k
    faces k (k = i0) = p i

homotopy-conjugate-Square : {f g : A  B}
   (H : (x : A)  (f x  g x))
   {a b c d : A}
   {r : a  c} {s : b  d}
   {t : a  b} {u : c  d}
   Square (ap f t) (ap f u) (ap f r) (ap f s)
   Square (ap g t) (ap g u) (ap g r) (ap g s)
homotopy-conjugate-Square {B = B} H {r = r} {s} {t} {u} sq i j 
  = hcomp ( i   j) faces
  where
    faces : (k : I)  Partial ( i   j  ~ k) B
    faces k (j = i0) = H (r i) k
    faces k (j = i1) = H (s i) k
    faces k (i = i0) = H (t j) k
    faces k (i = i1) = H (u j) k
    faces k (k = i0) = sq i j

Aside: Alternatively, produce a path

  Square (ap f t) (ap f u) (ap f r) (ap f s) 
≡ Square (ap g t) (ap g u) (ap g r) (ap g s)

and apply transport.

isSet-retract : B RetractOnto A  isSet B  isSet A
isSet-retract r sB x y p q 
  = homotopy-conjugate-Square (r .section .proof) (ap-Square (r .map) (sB _ _ _ _))

isSet-equiv : A  B  isSet B  isSet A
isSet-equiv = isSet-retract  equiv→retract

And isSet-equiv lets us easily clear up , without fussing with defining an observational equality type ≡ℤ:

isSet-ℤ : isSet 
-- Exercise: (Hint: Find a useful equivalence in Lecture 2-X)
-- isSet-ℤ = isSet-equiv {!!} {!!}

Hedberg’s Theorem

There’s a very slick criterion for when a type is a set: Hedberg’s Theorem, which states that any type with decidable equality is a set. A type has decidable equality whenever the type of paths between any two points is decidable:

Dec≡ : Type   Type 
Dec≡ A = (x y : A)  Dec (x  y)

We are assuming that the path types are all decidable, but not that they are decidable propositions. (After all, if we already knew they were propositions then we would already know our type is a set.)

Here’s a simple example. We have seen that not all propositions are decidable, but all propositions have decidable equality. Given two elements of a proposition it is easy to decide whether they are equal, the answer is always yes!

isProp→Dec≡ : isProp A  Dec≡ A
-- Exercise:
-- isProp→Dec≡ pA = {!!}

Inductive types often have decidable equality. The proofs are much like the (very similarly named) Dec-≡Bool and Dec-≡ℕ definitions from earlier, which we wrote before we had the notion of paths.

Dec≡-Bool : Dec≡ Bool
-- Exercise:
-- Dec≡-Bool = {!!}

Dec≡-ℕ : Dec≡ 
-- Exercise:
-- Dec≡-ℕ = {!!}

We will prove Hedberg’s Theorem using a slick argument that we learned from Favonia. Here is the idea. Start with a path p : x ≡ y. By assumption, x ≡ y is decidable, so we also have an element of Dec (x ≡ y). This can’t be no, because that would cause a contradiction: after all, we already know that x ≡ y via p.

So we have yes q : Dec (x ≡ y), where q : x ≡ y is also a path between the same points. But here is the key: this path q is the same, regardless of which p we start with.

Start by defining a function that either replaces a path p with the q from Dec (x ≡ y) or derives a contradiction.

Dec≡-bad-replacement : {x y : A}  Dec (x  y)  x  y  x  y
-- Exercise:
-- Dec≡-bad-replacement d p = {!!}

Next, we want to show that this replacement is equal to the path that we started with. The plan is to do this using J, but for that to work we need the replacement to equal refl when p is itself refl. Right now it isn’t: instead, the replacement is just Dec≡-bad-replacement (dec x x) refl : x ≡ x, which doesn’t simplify.

This is easily fixed. Define a function that gives a good replacement path, by composing the old definition with the inverse of the path Dec≡-bad-replacement (dec x x) refl that we want to get rid of:

Dec≡-good-replacement : Dec≡ A  {x y : A}  x  y  x  y
-- Exercise:
-- Dec≡-good-replacement dec {x} {y} p = {!!}

Dec≡-replacement-undo : (dec : Dec≡ A)  {x y : A}  (p : x  y)  Dec≡-good-replacement dec p  p
-- Exercise:
-- Dec≡-replacement-undo dec {x} {y} p = J (λ y p → Dec≡-good-replacement dec p ≡ p) {!!} {!!}

The final lemma is that these good replacements are all equal to each other, regardless of what path you start with. This is easy after pattern-matching on Dec (x ≡ y).

Dec≡-replacement-same : (dec : Dec≡ A)  {x y : A}  (p₁ p₂ : x  y)
   Dec≡-good-replacement dec p₁  Dec≡-good-replacement dec p₂
-- Exercise:
-- Dec≡-replacement-same dec {x} {y} p₁ p₂ = {!!}

  where helper : (w : Dec (x  y)) 
            sym (Dec≡-bad-replacement (dec x x) refl)  Dec≡-bad-replacement w p₁
           sym (Dec≡-bad-replacement (dec x x) refl)  Dec≡-bad-replacement w p₂
--      Exercise:
--      helper d = {!!}

Now glue these pieces together to finish the proof.

hedberg : Dec≡ A  isSet A
hedberg dec x y p₁ p₂ =
-- Exercise:
--   p₁                           ≡⟨ {!!} ⟩
--   Dec≡-good-replacement dec p₁ ≡⟨ {!!} ⟩
--   Dec≡-good-replacement dec p₂ ≡⟨ {!!} ⟩
--   p₂ ∎

Higher Types

You may have noticed a pattern developing in the last couple of Lectures. We start with the simplest possible types, the ones satisfying isContr. These contain no information at all.

More complicated are the propositions identified by isProp. In isProp→isContr≡ and isContr≡→isProp, we observed that these are the types whose path types are contractible. More complicated again are the sets, identified by isSet. By definition these are the types whose path types are propositions. We can continue this pattern inductively, stratifying types by what is known as their h-level.

isHLevel :   Type   Type 
isHLevel zero    X = isContr X
isHLevel (suc n) X = (x y : X)  isHLevel n (x  y)

So types with h-level 0 are contractible, with h-level 1 are propositions, and with h-level 2 are sets.

This definition doesn’t exactly match isProp when n = 1, but as we saw in isProp→isContr≡ and isContr≡→isProp, it is equivalent. An alternative definition would specify

isHLevel (suc zero) X = isProp X

directly rather than leaving that to the inductive case. We’ll stick with the simpler definition so that we have one fewer case to deal with in our proofs. It is easy enough to patch over the difference.

isProp→isHLevel1 : isProp A  isHLevel 1 A
isProp→isHLevel1 = isProp→isContr≡

isHLevel1→isProp : isHLevel 1 A  isProp A
isHLevel1→isProp = isContr≡→isProp

isSet→isHLevel2 : isSet A  isHLevel 2 A
isSet→isHLevel2 sA x y = isProp→isHLevel1 (sA x y)

isHLevel2→isSet : isHLevel 2 A  isSet A
isHLevel2→isSet hA x y = isHLevel1→isProp (hA x y)

Caution: In homotopy theory, a different numbering system is used for h-levels, so that the hierarchy shifted down by two. A set, i.e. a type with h-level 2, is said to have “truncation level 0”, and a proposition has “truncation level -1”. Sometimes this is shortened even further, so that a set is a “0-type” and a proposition is a “(-1)-type”. This is just a difference in conventions, but will be necessary to keep in mind when reading other resources.

isHLevel-suc : (n : )  isHLevel n A  isHLevel (suc n) A
-- Exercise:
-- isHLevel-suc n = {!!}

isProp-isHLevel : (n : )  isProp (isHLevel n A)
-- Exercise:
-- isProp-isHLevel n = {!!}
isHLevel-retract : (n : )  B RetractOnto A  isHLevel n B  isHLevel n A
-- Exercise:
-- isHLevel-retract n = {!!}

isHLevel-equiv : (n : )  (A  B)  isHLevel n B  isHLevel n A
-- Exercise:
-- isHLevel-equiv = {!!}

isHLevel-Σ : {A : Type }  {B : A  Type ℓ'} 
   (n : ) 
   isHLevel n A 
   ((x : A)  isHLevel n (B x))
   isHLevel n (Σ[ x  A ] B x)
-- Exercise:
-- isHLevel-Σ n = {!!}

isHLevel-Π : {B : A  Type }  
   (n : )
   ((x : A)  isHLevel n (B x))
   isHLevel n ((x : A)  B x)
-- Exercise:
-- isHLevel-Π n = {!!}

isHLevel-≡ : (n : )
   isHLevel n A
   (x y : A)  isHLevel n (x  y)
isHLevel-≡ zero hA = isContr→isContr≡ hA
isHLevel-≡ (suc n) hA x y = isHLevel-suc n (hA x y)

isHLevel-PathP : {A : I  Type }
   (n : )
   ((i : I)  isHLevel n (A i))
   (x : A i0)  (y : A i1)  isHLevel n (PathP A x y)
isHLevel-PathP zero hA = isContr→isContr-PathP (hA i1)
isHLevel-PathP (suc n) hA x y = isHLevel-equiv (suc n) (PathP≃Path _) (isHLevel-≡ n (hA i1 _ _))
isConnected-S¹ : (s : )   (base  s)
isConnected-S¹ base = in-∃ refl 
isConnected-S¹ (loop i) = squash (in-∃ λ j  loop (i  j)) (in-∃ λ j  loop (i  ~ j)) i

isHLevel3-S¹ : isHLevel 3 
isHLevel3-S¹ = step-3
  where 
    step-1 : isHLevel 2 (base  base)
    step-1 = isSet→isHLevel2 (isSet-equiv ΩS¹≃ℤ isSet-ℤ)

    step-2 : (y : )  isHLevel 2 (base  y)
    step-2 y = ∃-rec (isProp-isHLevel 2)  q  subst  t  isHLevel 2 (base  t)) q step-1) (isConnected-S¹ y)

    step-3 : (x y : )  isHLevel 2 (x  y)
    step-3 x y = ∃-rec (isProp-isHLevel 2)  p  subst  x  isHLevel 2 (x  y)) p (step-2 y)) (isConnected-S¹ x)
record Prop ( : Level) : Type (ℓ-suc ) where
  constructor propData
  field
    witness : Type 
    witnessIsProp : isProp witness
open Prop public

mvrnote: good examples?

Univalence allows us to prove that the type of propositions is a set.

First, being an equivalence between propositions it itself a proposition. (In fact, this is true for functions between any types, as we prove with a lot more effort in Lecture 2-X, but it is easy enough to prove directly for the case we need it here.)

-- isProp-isEquiv-for-Props : isProp P → isProp Q → (f : P → Q) → isProp (IsEquiv f)
-- -- Exercise: (Hint: Combine `isProp-Σ` and `isProp-Π` a few times.)
-- -- isProp-isEquiv-for-Props pP pQ f = {!!}
-- isProp-isEquiv-for-Props pP pQ f = isProp× (isPropΣ (isProp→ pP) (λ s → isPropΠ λ b → isProp→isSet pQ _ _))
--                                            (isPropΣ (isProp→ pP) (λ r → isPropΠ λ a → isProp→isSet pP _ _))
mvrnote: missing?

Suspensions

mvrnote: where should this go? all the suspension examples work fine once we have composition

data Susp { : Level} (A : Type ) : Type  where
  north : Susp A
  south : Susp A
  merid : (a : A)  north  south

Susp-map : { : Level} {X Y : Type }  (f : X  Y)  Susp X  Susp Y
Susp-map f north = north
Susp-map f south = south
Susp-map f (merid a i) = merid (f a) i

The simplest example is when we feed Susp the empty type . You can use an absurd pattern in the merid case.

Susp∅≃Bool : Susp   Bool
-- Exercise (trivial):
-- Susp∅≃Interval = {!!}
Susp∅≃Bool = inv→equiv fun inv to-fro fro-to
  where
    fun : Susp   Bool
    fun north = true
    fun south = false
    fun (merid () i)
    inv : Bool  Susp 
    inv true = north
    inv false = south
    to-fro : isSection fun inv
    to-fro true = refl
    to-fro false = refl
    fro-to : isRetract fun inv
    fro-to north = refl
    fro-to south = refl
    fro-to (merid () i)

Next simplest is the unit type , where the result looks like the following:

Susp⊤≃Interval : Susp   Interval
-- Exercise (also trivial):
-- Susp⊤≃Interval = {!!}
Susp⊤≃Interval = inv→equiv fun inv to-fro fro-to
  where
    fun : Susp   Interval
    fun north = zero
    fun south = one
    fun (merid tt i) = seg i
    inv : Interval  Susp 
    inv zero = north
    inv one = south
    inv (seg i) = merid tt i
    to-fro : isSection fun inv
    to-fro zero = refl
    to-fro one = refl
    to-fro (seg i) = refl
    fro-to : isRetract fun inv
    fro-to north = refl
    fro-to south = refl
    fro-to (merid tt i) = refl

And we have seen that the Interval type is contractible.

isContr→isContr-Susp : isContr A  isContr (Susp A)
isContr→isContr-Susp cA .center = north
isContr→isContr-Susp cA .contraction north = refl  refl
isContr→isContr-Susp cA .contraction south = (merid (cA .center))  refl
isContr→isContr-Susp cA .contraction (merid a i) = connection∧ (merid (cA .center)) i  ap  t  merid t i ) (cA .contraction a)
-- eg: https://1lab.dev/Homotopy.Space.Suspension.Properties.html
-- isProp→isSet-Susp : isProp A → isSet (Susp A)
-- isProp→isSet-Susp pA x y p q = {!!}

Finally something interesting happens once we try Bool.

SuspBool≃S¹ : Susp Bool  
-- Exercise:
-- SuspBool≃S¹ = {!!}
data S∞ : Type where
  snorth : S∞
  ssouth : S∞
  smerid : S∞  snorth  ssouth

S∞SelfSusp : S∞  Susp S∞
S∞SelfSusp = inv→equiv to fro to-fro fro-to
  where
    to : S∞  Susp S∞
    to snorth = north
    to ssouth = south
    to (smerid s i) = merid s i
    fro : Susp S∞  S∞
    fro north = snorth
    fro south = ssouth
    fro (merid a i) = smerid a i
    to-fro : isSection to fro
    to-fro north = refl
    to-fro south = refl
    to-fro (merid a i) = refl
    fro-to : isRetract to fro
    fro-to snorth = refl
    fro-to ssouth = refl
    fro-to (smerid a i) = refl

isContr-S∞ : isContr S∞
isContr-S∞ .center = snorth
isContr-S∞ .contraction = go
  where go : (y : S∞)  snorth  y
        go snorth = refl  refl
        go ssouth = smerid snorth  refl
        go (smerid s i) = connection∧ (smerid snorth) i  ap  t  smerid t i) (go s)

Even Higher types

EH-base : { : Level} {A : Type } {x : A}
   (α β : refl {x = x}  refl)
   Square  i  refl  β i) 
            i  refl  β i) 
            i  α i  refl) 
            i  α i  refl)
EH-base α β i j = α i  β j

EH : { : Level} {A : Type } {x : A}
   (α β : refl {x = x}  refl)
   Square β β α α
EH α β i j = hcomp ( i   j)  k  λ
    { (i = i0)  ∙-idl (β j) (~ k)
    ; (i = i1)  ∙-idl (β j) (~ k)
    ; (j = i0)  ∙-idr (α i) (~ k)
    ; (j = i1)  ∙-idr (α i) (~ k)
    ; (k = i0)  EH-base α β i j})

Egbert exercises:

Show that a type 𝑋 is a set if and only if the map 𝜆𝑥. 𝜆𝑡. 𝑥 : 𝑋 → (S1 → 𝑋) is an equivalence.

mvrnote: general hlevels?

References and Further Reading

mvrnote:

Hedberg’s Theorem: https://doi.org/10.1017/S0956796898003153