open import 1Lab.Path.Groupoid open import 1Lab.Univalence open import 1Lab.Type.Dec open import 1Lab.Equiv open import 1Lab.Path open import 1Lab.Type open import Data.Int.Inductive open import Data.Bool open import Data.Bool module 1Lab.HIT.S1 where
The Circle🔗
Since the “intended interpretation” of HoTT is in a -category of “good spaces”, it makes sense that HoTT has facilities for describing spaces. These are the higher inductive types, one of which is the circle:
data S¹ : Type where base : S¹ loop : base ≡ base
Diagramatically, we can picture the circle as being the -groupoid generated by the following diagram:
In type theory with K, the circle is exactly the same type as ⊤. However, with univalence, it can be shown that the circle has two different paths:
möbius : S¹ → Type möbius base = Bool möbius (loop i) = ua (not , not-is-equiv) i
When pattern matching on the circle, we are asked to provide a basepoint b
and a path l : b ≡ b
, as can be seen in the definition above. To make it clearer, we can also define a recursion principle:
S¹-rec : ∀ {ℓ} {A : Type ℓ} (b : A) (l : b ≡ b) → S¹ → A S¹-rec b l base = b S¹-rec b l (loop i) = l i
Using möbius, it can be shown that the loop is not refl:
parity : base ≡ base → Bool parity l = subst möbius l true _ : parity refl ≡ true _ = refl _ : parity loop ≡ false _ = refl refl≠loop : refl ≡ loop → ⊥ refl≠loop path = true≠false (ap parity path)
The circle is also useful as a source of counterexamples. By S¹-elim', we can prove that there is an inhabitant of (x : S¹) → x ≡ x
which is not constantly refl
S¹-elim : ∀ {ℓ} {P : S¹ → Type ℓ} → (pb : P base) → PathP (λ i → P (loop i)) pb pb → (x : S¹) → P x S¹-elim pb pl base = pb S¹-elim pb pl (loop i) = pl i S¹-elim' : ∀ {ℓ} {P : S¹ → Type ℓ} (pb : P base) → subst P loop pb ≡ pb → (x : S¹) → P x S¹-elim' {P = P} pb pl = S¹-elim pb (transport (λ i → PathP≡Path (λ i → P (loop i)) pb pb (~ i)) pl) always-loop : (x : S¹) → x ≡ x always-loop = S¹-elim' loop (subst-path-both _ _ ∙ lemma) where lemma = sym loop ∙ loop ∙ loop ≡⟨ ∙-cancel-l loop loop ⟩≡ loop ∎
Path Space🔗
A classical result of algebraic topology is that the fundamental group of the circle is isomorphic to the group of integers. In Homotopy Type Theory, we can repeat this proof: The type of integers codes for paths in the circle.
module S¹Path where Cover : S¹ → Type Cover base = Int Cover (loop i) = ua suc-equiv i
We define a map encode which converts a path in the circle to an element of the Cover. By lifting p to the Cover, we determine a path Int ≡ Int
, which we apply to zero:
encode : (x : S¹) → base ≡ x → Cover x encode x p = subst Cover p (pos zero)
This map counts the winding number of a path:
_ : encode base refl ≡ pos zero _ = refl _ : encode base loop ≡ pos (suc zero) _ = refl
In the other direction, we define a map decode which converts an integer to a path base ≡ base
:
loop^ : Int → base ≡ base loop^ (pos zero) = refl loop^ (pos (suc x)) = loop^ (pos x) ∙ loop loop^ (negsuc zero) = sym loop loop^ (negsuc (suc x)) = loop^ (negsuc x) ∙ sym loop
What we want to show is that encode base
and loop^
are mutual inverses. For this, we must show that encode base (loop^ n) ≡ n
and loop^ (encode base p) ≡ p
. The former direction is simpler, because we can show it directly by recursion on Int:
encode-loop^ : (n : Int) → encode base (loop^ n) ≡ n encode-loop^ (pos zero) = refl encode-loop^ (pos (suc x)) = ap suc-int (encode-loop^ (pos x)) encode-loop^ (negsuc zero) = refl encode-loop^ (negsuc (suc x)) = ap pred-int (encode-loop^ (negsuc x))
In the other direction, we would like to apply path induction to reduce the problem to showing loop^ (encode base refl) ≡ refl
. However, path induction does not apply to paths base ≡ base
, only to paths base ≡ x
, where x
a variable. Therefore, we have to generalise the function loop^
to the function decode.
decode : (x : S¹) → Cover x → base ≡ x decode base = loop^
On the basepoint, the type of the right-hand side computes to Int → base ≡ base
; Thus, we can use the existing loop^ map.
decode (loop i) n j = square where
For the loop case, recall the induction principle of the circle. We must provide a path loop^ ≡ loop^
“laying over” loop, i.e. a Square refl (loop^ n) (loop^ n) loop
. Visually, we can picture the boundary of the path we must provide as the square below:
We will construct this square in parts. First, we’ll construct a square loop^-square with the boundary below, for any , by recursion on the integer ; We’ll then modify this square so it becomes the one above.
loop^-square : (n : Int) → Square refl (loop^ (pred-int n)) (loop^ n) loop loop^-square (pos zero) i j = loop (i ∨ ~ j)
The case above is for . We can picture it as follows. Note that this is a square where two faces are the path loop and two faces are degenerate: a connection.
loop^-square (pos (suc x)) i j = hfill (λ k → λ { (j = i0) → base ; (j = i1) → loop k }) (inS (loop^ (pos x) j)) i
In the case where , the square we have to fill is the one on the left below, but note that the composite on the right face is defined to be the dashed path in that square; Thus, the filler of that square suffices. A similar thing happens for the case where , which is the square on the right.
loop^-square (negsuc x) i j = hfill (λ k → λ { (j = i0) → base ; (j = i1) → loop (~ k) }) (inS (loop^ (negsuc x) j)) (~ i)
We can then alter the square loop^-square to the square we want, by sketching an appropriate cube.
square = hcomp (λ k → λ { (i = i0) → loop^ (pred-suc n k) j ; (i = i1) → loop^ n j ; (j = i0) → base ; (j = i1) → loop i }) (loop^-square (unglue (i ∨ ~ i) n) i j)
With this generalised decode, we can prove that decode x (encode x p) ≡ p
, by reducing p
to refl, i.e. path induction.
decode-encode : {x : S¹} (p : base ≡ x) → decode x (encode x p) ≡ p decode-encode = J (λ y p → decode y (encode y p) ≡ p) refl
Thus we have that the loop space of the circle is the type of integers:
ΩS¹≃Int : (base ≡ base) ≃ Int ΩS¹≃Int = Iso→Equiv (encode base , iso loop^ encode-loop^ decode-encode)