Loops that cannot be undone
A goat tethered by a long rope wanders around a field in the hills above Arusha and, by evening, has walked twice around a tree. The rope is now wrapped twice around the trunk. However the goat wanders, it cannot unwrap the rope without walking back around the tree. Had there been no tree, every tangle could have been pulled straight. The obstruction is the hole in the field where the trunk stands, and the number of turns is a whole number that no continuous wandering can change.
That simple picture leads to deep theorems. Lay a paper map of Santiago flat on a table in Santiago: some point on the map lies exactly above the point of the city it represents. Stir a cup of tea without splashing (and think of the surface as a disc): at every moment some point of the surface is back where it started. These are instances of Brouwer's fixed-point theorem. Its proof in two dimensions is a statement about loops around a hole.
The previous lesson, metric spaces and point-set topology, could tell from by removing a point and counting the pieces. It could not tell from : both stay connected when a point is removed. What differs is the loops. In a loop around the origin cannot be shrunk to a point; in every loop can (slip it over the "top"). Henri Poincaré turned this into algebra in 1895. To each space with a basepoint he attached a group, the fundamental group , whose elements are loops up to continuous deformation. This lesson builds that group, computes it for the circle, and uses it.
Deforming loops
Take the plane with a hole at the origin, and loops that start and end at a basepoint . Two loops are homotopic if one can be continuously deformed into the other, keeping the basepoint fixed and never crossing the hole. A loop that does not go around the hole can be shrunk to the constant loop. A loop that goes around once anticlockwise cannot — but any two such loops can be deformed into each other, however much they wiggle. What survives deformation is the winding number: how many times the loop goes around the hole, counted with sign.
Loops can be composed: run , then . Winding numbers add. Every loop has an inverse, the same loop run backwards, and followed by its reverse can be shrunk away. So the deformation classes of loops form a group, and for the punctured plane — or for the circle — it should be . Proving that the winding number is really well defined, and that it classifies loops completely, is the heart of the lesson. The tool is a covering map: the real line wound round and round above the circle like a spiral staircase. A loop in the circle is followed upstairs, and how many floors it climbs is its winding number.
Homotopy, paths and the fundamental group
Throughout, and all maps are continuous.
Definition— homotopy
A homotopy between maps is a map with and ; then . A map is null-homotopic if it is homotopic to a constant map. A homotopy equivalence is a map with a map such that and . A space is contractible if it is homotopy equivalent to a point.
Definition— paths and path homotopy
A path from to is a map with and ; a loop at is a path from to . Two paths from to are path-homotopic, , if there is a homotopy with
So the endpoints stay fixed throughout. Write for the path-homotopy class of .
Definition— concatenation and reverse
If ends where begins, the concatenation runs at double speed, then :
It is continuous by the pasting lemma. The reverse of is , and denotes the constant path at .
Definition— fundamental group
The fundamental group is the set of path-homotopy classes of loops at , with the product . A map induces , . A path-connected space with trivial fundamental group is simply connected.
Definition— covering map
A map is a covering map if every has an open neighbourhood that is evenly covered: is a disjoint union of open sets (the sheets over ), each mapped homeomorphically onto by . A lift of a map is a map with .
Example— The basic covering
, , is a covering map. For , the open arc of points with is evenly covered: is the disjoint union of the intervals , . So is from to itself, for : every point has preimages, and small arcs are evenly covered.
A first gallery
The theorems below justify every entry of this table.
| Space | Reason | |
|---|---|---|
| , a convex set, a disc | trivial | straight-line homotopy (Example below) |
| circle , punctured plane, annulus | Theorem 6 (and homotopy equivalence) | |
| torus | product formula; also van Kampen | |
| figure eight | free group on two generators | van Kampen (Theorem 9) |
| sphere , | trivial | van Kampen |
| real projective plane | van Kampen, or the double cover | |
| closed orientable surface of genus | van Kampen |
Example— Convex sets are simply connected
If is convex and are paths in from to , then stays in (by convexity), is continuous, equals at and at , and keeps the endpoints fixed because . So any two paths with the same endpoints are path-homotopic; in particular every loop is null-homotopic. This straight-line homotopy is formalised in Lean below.
Example— Products
A loop in is a pair of loops, and a path homotopy is a pair of path homotopies, so . For the torus this gives : a loop is determined up to homotopy by how many times it goes around "the long way" and "the short way".
Example— Same group, different spaces
and a single point both have trivial fundamental group, but they are not homeomorphic (and not even homotopy equivalent: has a non-trivial second homotopy group). The fundamental group is an invariant, not a complete classification.
The fundamental group is a group, and an invariant
Theorem— Lemma 1 (reparametrisation)
If is continuous with and , then for every path .
Proof
is defined because is convex, it is continuous, it equals at and at , and , .
∎
Theorem— Theorem 2 (π₁ is a group)
Path homotopy is an equivalence relation, concatenation is well defined on classes, and is a group with identity and inverses .
Proof
Equivalence relation. Reflexivity: . Symmetry: . Transitivity: run a homotopy from to for and one from to for , at double speed.
Well defined. If is a path homotopy from to and from to , then placing on and on (with rescaled) gives a path homotopy from to ; the pieces agree on , where both equal the common endpoint.
Associativity. runs on , while uses . So , where is piecewise linear, mapping , and . Apply Lemma 1.
Identity. with , and similarly for . Apply Lemma 1.
Inverses. for and for agree at , equal at and the constant loop at , and fix both ends at . So , and likewise .
∎
Theorem— Proposition 3 (basepoints)
A path from to gives an isomorphism , . So for path-connected the group does not depend on , up to isomorphism.
Proof
, using and the group laws of Theorem 2 (which hold for paths, not only loops, with the same proofs). The inverse of is .
∎
The isomorphism depends on the homotopy class of : changing composes with conjugation by a loop. So when is non-abelian, "the" fundamental group of a path-connected space is defined only up to non-canonical isomorphism.
Theorem— Proposition 4 (functoriality and homotopy invariance)
(a) is a homomorphism, and . (b) If is a homotopy from to with for all , then . (c) A homotopy equivalence induces an isomorphism .
Proof
(a) , and carries path homotopies to path homotopies. The other two equations hold already on loops.
(b) For a loop at , is a path homotopy from to ; its ends stay at .
(c) When a homotopy from to does not fix the basepoint, one shows instead that , where is the track of the basepoint; see Hatcher (2002), Lemma 1.19. Now let be a homotopy inverse of . Applying this to shows that is a change-of-basepoint isomorphism, so is surjective. Applying it to shows that is an isomorphism, so the same is injective. Hence is an isomorphism, and so is .
∎
In particular contractible spaces are simply connected, and the punctured plane, the annulus and the solid torus all have the same fundamental group as the circle — each deformation retracts onto a circle.
Lifting, and the fundamental group of the circle
Theorem— Theorem 5 (path and homotopy lifting)
Let be a covering map. (a) For every path in and every there is a unique lift with . (b) For every map and every there is a unique lift with . If is a path homotopy, so is .
Proof
(a) Existence. The sets , for evenly covered, form an open cover of the compact metric space . By the Lebesgue number lemma there is a subdivision such that each lies in one evenly covered set . Suppose is defined on . Let be the sheet over that contains , and set on . The two definitions agree at , so the pasting lemma keeps continuous. After steps, is defined on .
Uniqueness. Let be lifts with the same start, and , which contains . Given , choose an evenly covered and the sheets , . On a small interval around , both lifts stay in their sheets. If , both equal on , so . If the sheets are disjoint, so . Hence and its complement are open; is connected, so .
(b) The same argument on the square: subdivide into small squares, each mapped into an evenly covered set, and lift them one at a time, row by row; each new square meets the part already lifted in a connected set (an edge, or two edges), so the lift agrees there. Uniqueness follows from (a) applied to the segments and . If is a path homotopy, then and are constant, and by uniqueness so are their lifts. Details: Hatcher (2002), Proposition 1.30.
∎
Theorem— Theorem 6 (Poincaré: the fundamental group of the circle)
. The isomorphism sends the class of a loop to its degree: , where is the lift of to with under .
Proof
The lift ends in , so is an integer.
Well defined. If is a path homotopy from to , lift it with (Theorem 5b). By uniqueness, and . The path lifts the constant path at , so it lies in the discrete set ; a path in a discrete space is constant. Hence .
Homomorphism. Let lift from to and lift from to . The translate also lifts (as ), from to . So lifts from to : .
Surjective. The loop lifts to , so it has degree .
Injective. If , then is a loop at in , and is a path homotopy from to the constant loop. Then is a path homotopy from to the constant loop.
∎
The same proof, with the covering , , shows that , with the winding number as the isomorphism.
Brouwer and the fundamental theorem of algebra
Theorem— Corollary 7 (no retraction; Brouwer's fixed-point theorem)
(a) There is no map with for all . (b) Every map of the closed disc to itself has a fixed point.
Proof
(a) Let be the inclusion. If , then on (Proposition 4a). But lands in , which is trivial (the disc is convex). So the identity of would factor through the trivial group, which is absurd.
(b) Suppose for every . Let be the point where the ray from through leaves the disc. Explicitly, with , , where solves :
The square root is of a non-negative continuous function (as ), so is continuous. If , then (Cauchy–Schwarz and ), so and . Thus is a retraction of onto , contradicting (a).
∎
The same theorem holds for the closed ball in every dimension, with replaced by higher homotopy or homology groups; in dimension one it is just the intermediate value theorem (formalised below as brouwer_interval). The hypotheses matter: a rotation of an annulus, the antipodal map of a sphere and the map of the open disc have no fixed points.
Theorem— Corollary 8 (fundamental theorem of algebra)
Every non-constant polynomial with complex coefficients has a complex root.
Proof
We may take with . Suppose has no root. For define the loop
in at . As varies, is a path homotopy between any two of these loops, and is constant. So in for all .
Now fix . For ,
so has no zero on for . Replacing by in the formula for gives a path homotopy from (at ) to (at ), whose degree is . This contradicts .
∎
Gluing spaces: van Kampen, and covering spaces
To compute of a space built from simpler pieces, one glues the groups.
Theorem— Theorem 9 (Seifert–van Kampen; stated, proof referenced)
Let with open and path-connected, path-connected, and . Then the inclusions induce an isomorphism
the free product of and modulo the relations for .
The proof subdivides a loop, or a homotopy, into pieces lying in or in by the Lebesgue number lemma; see Hatcher (2002), Theorem 1.20. In practice it is used like this:
- Wedge of circles. For , take and to be each circle together with a short open arc of the other at the wedge point. Each deformation retracts to a circle and is contractible, so , the free group on two generators : its elements are reduced words such as . In particular , so fundamental groups need not be abelian.
- Spheres. For , , take and to be the complements of the north and south poles. Each is homeomorphic to , and is path-connected when . So is trivial. (For the intersection is two arcs and the theorem does not apply — rightly so.)
- Surfaces. The torus is a square with sides glued by the word . Take to be the open square and a neighbourhood of the glued boundary, which deformation retracts onto the figure eight . Then is an annulus, whose generator goes once around the boundary of the square, i.e. maps to in . So . The genus- surface, a -gon glued by , has , whose abelianisation is . Different genera give different groups, so the surfaces are pairwise non-homeomorphic. The projective plane, a disc with antipodal boundary points glued (word ), has .
Covering spaces turn into a Galois-like correspondence.
Theorem— Theorem 10 (classification of covering spaces; stated, proof referenced)
Let be path-connected, locally path-connected and semilocally simply connected, with basepoint . Then is a bijection from isomorphism classes of connected based covering spaces onto subgroups of . Forgetting basepoints, connected coverings correspond to conjugacy classes of subgroups. The number of sheets equals the index of the subgroup. The trivial subgroup corresponds to the simply connected universal cover , whose group of deck transformations is isomorphic to .
The proof (Hatcher 2002, Theorem 1.38) constructs as the space of homotopy classes of paths starting at and obtains the other coverings as its quotients. Examples: the coverings of are (subgroup ) and (subgroup ); the universal cover of the torus is the plane, with deck group acting by translations. An -sheeted covering of the figure eight is described by two permutations of the sheets (where the lifts of and lead), and it is connected when they act transitively — the second experiment below counts them.
Homotopy in Lean and Mathlib
Mathlib's notions match the lesson's, with one difference of convention: a homotopy takes the time first. Path x y is a bundled continuous map from the unit interval with the right endpoints, Path.Homotopy p q a homotopy rel endpoints, and FundamentalGroup X x the automorphism group of x in the fundamental groupoid (so is literally a groupoid's vertex group — see the categories viewpoint).
The straight-line homotopy of the convex-set example, and its consequences. The helper lemma is the identity that keeps endpoints fixed:
/-- The convex combination of a vector with itself is that vector: `(1 - t) • v + t • v = v`.
This is why a straight-line homotopy keeps the endpoints of paths fixed. -/
theorem smul_combo_self {E : Type*} [AddCommGroup E] [Module ℝ E] (t : ℝ) (v : E) :
(1 - t) • v + t • v = v := by
rw [← add_smul, sub_add_cancel, one_smul]/-- **The straight-line homotopy.** Two paths `p`, `q` from `x` to `y` in a real normed space are
deformed into each other by `H(t, s) = (1 - t) • p(s) + t • q(s)`: at time `t = 0` it is `p`, at
`t = 1` it is `q`, and at every time the endpoints stay at `x` and `y`. -/
noncomputable def straightLineHomotopy {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E]
{x y : E} (p q : Path x y) : p.Homotopy q where
toFun z := (1 - (z.1 : ℝ)) • p z.2 + (z.1 : ℝ) • q z.2
continuous_toFun := by fun_prop
map_zero_left s := by simp
map_one_left s := by simp
prop' t s hs := by
rcases hs with rfl | hs
· simp only [ContinuousMap.coe_mk, Path.coe_toContinuousMap, Path.source]
exact smul_combo_self _ _
· rw [Set.mem_singleton_iff] at hs
subst hs
simp only [ContinuousMap.coe_mk, Path.coe_toContinuousMap, Path.target]
exact smul_combo_self _ _/-- In a real normed space any two paths with the same endpoints are homotopic rel endpoints,
via `straightLineHomotopy`. -/
theorem paths_homotopic_in_vector_space {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E]
{x y : E} (p q : Path x y) : p.Homotopic q :=
⟨straightLineHomotopy p q⟩/-- Every loop in a real normed space (such as `ℝⁿ`, or the plane containing a disc) is
homotopic to the constant loop: the fundamental group is trivial. -/
theorem loop_nullhomotopic {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] {x : E}
(γ : Path x x) : γ.Homotopic (Path.refl x) :=
paths_homotopic_in_vector_space γ (Path.refl x)/-- A real normed space is simply connected. Mathlib gets this from contractibility
(`RealTopologicalVectorSpace.contractibleSpace` and `SimplyConnectedSpace.ofContractible`). -/
theorem vector_space_simply_connected (E : Type*) [NormedAddCommGroup E] [NormedSpace ℝ E] :
SimplyConnectedSpace E :=
inferInstanceFunctoriality (Proposition 4a) and change of basepoint (Proposition 3):
/-- **Functoriality.** The homomorphism induced by a composite `g ∘ f` is the composite of the
induced homomorphisms: `(g ∘ f)_* = g_* ∘ f_*`. In Mathlib `FundamentalGroup.map f x` sends the
class of a loop `γ` to the class of `f ∘ γ`; both sides send the class of `γ` to the class of
`g ∘ f ∘ γ`, so we check the equation on a representative loop. -/
theorem map_comp {X Y Z : Type*} [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z]
(f : C(X, Y)) (g : C(Y, Z)) (x : X) :
FundamentalGroup.map (g.comp f) x = (FundamentalGroup.map g (f x)).comp
(FundamentalGroup.map f x) := by
ext γ
rcases γ with ⟨γ⟩
induction γ using Path.Homotopic.Quotient.ind with
| mk p => rfl/-- **Change of basepoint.** A path `p` from `x₀` to `x₁` gives an isomorphism
`π₁(X, x₀) ≅ π₁(X, x₁)`, sending a loop `γ` to `p⁻¹ · γ · p`. This applies Mathlib's
`FundamentalGroup.fundamentalGroupMulEquivOfPath`. -/
theorem change_of_basepoint {X : Type*} [TopologicalSpace X] {x₀ x₁ : X} (p : Path x₀ x₁) :
Nonempty (FundamentalGroup X x₀ ≃* FundamentalGroup X x₁) :=
⟨FundamentalGroup.fundamentalGroupMulEquivOfPath p⟩The circle is AddCircle 1, that is ; the covering is the quotient map. Mathlib proves the covering property, path lifting (Theorem 5a), and Theorem 6 itself, where the isomorphism is the winding number:
/-- Mathlib's circle `AddCircle p = ℝ/pℤ` needs to know that the period is positive. We use the
period `1`, so `AddCircle 1` is `ℝ/ℤ`. -/
instance fact_one_pos : Fact ((0 : ℝ) < 1) := ⟨one_pos⟩/-- **`ℝ → ℝ/ℤ` is a covering map**: each point of the circle has a neighbourhood whose preimage
is a disjoint union of copies of it, one for each integer translate. This applies Mathlib's
`AddCircle.isCoveringMap_coe`. -/
theorem covering_real_circle : IsCoveringMap ((↑) : ℝ → AddCircle (1 : ℝ)) :=
AddCircle.isCoveringMap_coe 1/-- **Path lifting.** Every path `γ` in the circle starting at the image of `e ∈ ℝ` lifts to a
path in `ℝ` starting at `e`. This applies Mathlib's `IsCoveringMap.exists_path_lifts`. -/
theorem path_lifting (γ : C(I, AddCircle (1 : ℝ))) (e : ℝ) (h : γ 0 = e) :
∃ Γ : C(I, ℝ), (↑) ∘ Γ = γ ∧ Γ 0 = e :=
covering_real_circle.exists_path_lifts γ e h/-- **`π₁(S¹) ≅ ℤ`.** The fundamental group of the circle `ℝ/ℤ`, at any basepoint, is
isomorphic to the integers; the isomorphism is the winding number. This applies Mathlib's
`AddCircle.windingNumberIso`, proved with the covering `ℝ → ℝ/ℤ` and the lifting theorems. -/
theorem pi1_circle (x : AddCircle (1 : ℝ)) :
Nonempty (FundamentalGroup (AddCircle (1 : ℝ)) x ≃* Multiplicative ℤ) :=
⟨AddCircle.windingNumberIso x⟩/-- The loop `t ↦ n t` (mod 1), which runs `n` times around the circle, has winding number `n`.
So the winding-number isomorphism is onto, and the loop running once around generates `π₁(S¹)`.
This applies Mathlib's `AddCircle.windingNumber_zsmulLoop`. -/
theorem windingNumber_loop (n : ℤ) :
AddCircle.windingNumber (x := ((0 : ℝ) : AddCircle (1 : ℝ)))
(.of (.mk (AddCircle.zsmulLoop (1 : ℝ) 0 n))) = n :=
AddCircle.windingNumber_zsmulLoop 0 nCorollary 7(a), proved here in a more general form: the circle is not a retract of any simply connected space. The proof is the lesson's, phrased with winding numbers: the loop going once around is carried to a null-homotopic loop with the same winding number. Since the disc is convex, hence simply connected, this is exactly the no-retraction theorem. What is not formalised is the step from no-retraction to Brouwer's theorem (the continuity of the ray construction in Corollary 7b).
/-- **The circle is not a retract of a simply connected space.** Suppose `i : S¹ → X` and
`r : X → S¹` are continuous with `r ∘ i = id`, and `X` is simply connected (for example, the
closed disc). Take the loop `γ` running once around the circle. Then `i ∘ γ` is null-homotopic
in `X`, so applying `r`, the loop `r ∘ i ∘ γ = γ` is null-homotopic in `S¹`. But homotopic loops
have the same winding number, and `γ` winds once while a constant loop winds zero times. -/
theorem circle_not_retract {X : Type*} [TopologicalSpace X] [SimplyConnectedSpace X]
(i : C(AddCircle (1 : ℝ), X)) (r : C(X, AddCircle (1 : ℝ))) (h : ∀ z, r (i z) = z) :
False := by
set x : AddCircle (1 : ℝ) := r (i ((0 : ℝ) : AddCircle (1 : ℝ))) with hx
let γ := AddCircle.zsmulLoop (1 : ℝ) 0 1
let δ : Path x x := (γ.map i.continuous).map r.continuous
-- `i ∘ γ` is null-homotopic in the simply connected space `X`; apply `r`.
have hδ : δ.Homotopic ((Path.refl (i ((0 : ℝ) : AddCircle (1 : ℝ)))).map r.continuous) :=
(SimplyConnectedSpace.paths_homotopic (γ.map i.continuous) (Path.refl _)).map r
-- So `δ` and the constant loop define the same element of `π₁(S¹, x)`.
have hclass : (FundamentalGroup.fromPath (.mk δ) : FundamentalGroup _ x) =
FundamentalGroup.fromPath (.mk ((Path.refl _).map r.continuous)) :=
congrArg _ (Quotient.sound hδ)
-- The winding number of `δ` is `1`: it has the lift `t ↦ t`, since `r ∘ i = id`.
have w1 : (AddCircle.windingNumber (FundamentalGroup.fromPath (.mk δ)) : ℝ) = 1 := by
have hw := AddCircle.windingNumber_eq_div δ ⟨fun t => (t : ℝ), continuous_subtype_val⟩ (by
funext t
change ((t : ℝ) : AddCircle (1 : ℝ)) = r (i (AddCircle.zsmulLoop 1 0 1 t))
rw [h, AddCircle.zsmulLoop_apply]
simp)
simpa using hw
-- The winding number of a constant loop is `0`: it has a constant lift.
have w0 : (AddCircle.windingNumber
(FundamentalGroup.fromPath (.mk ((Path.refl (i ((0 : ℝ) : AddCircle (1 : ℝ)))).map
r.continuous))) : ℝ) = 0 := by
obtain ⟨c, hc⟩ := QuotientAddGroup.mk_surjective x
have hw := AddCircle.windingNumber_eq_div ((Path.refl _).map r.continuous)
(ContinuousMap.const I c) (by
funext t
simp only [Function.comp_apply, ContinuousMap.const_apply, Path.map_coe,
Path.refl_apply]
exact hc)
simpa using hw
rw [hclass, w0] at w1
exact zero_ne_one w1Brouwer's theorem in dimension one, from the intermediate value theorem:
/-- **Brouwer's theorem in dimension one.** Every continuous map of `[0, 1]` into itself has a
fixed point. Apply the intermediate value theorem to `g(x) = f(x) - x`, which is `≥ 0` at `0`
and `≤ 0` at `1`. (Dimension one needs only connectedness; dimension two needs `π₁(S¹) ≅ ℤ`.) -/
theorem brouwer_interval (f : ℝ → ℝ) (hf : ContinuousOn f (Set.Icc 0 1))
(hmaps : ∀ x ∈ Set.Icc (0 : ℝ) 1, f x ∈ Set.Icc (0 : ℝ) 1) :
∃ x ∈ Set.Icc (0 : ℝ) 1, f x = x := by
have hg : ContinuousOn (fun x => f x - x) (Set.Icc 0 1) := hf.sub continuousOn_id
have h0 := hmaps 0 ⟨le_refl 0, zero_le_one⟩
have h1 := hmaps 1 ⟨zero_le_one, le_refl 1⟩
have hmem : (0 : ℝ) ∈ Set.Icc (f 1 - 1) (f 0 - 0) :=
⟨by linarith [h1.2], by linarith [h0.1]⟩
obtain ⟨x, hx, hfx⟩ := intermediate_value_Icc' zero_le_one hg hmem
exact ⟨x, hx, by linarith [hfx]⟩Finally, the free group on two generators — by van Kampen, of the figure eight — is not abelian. The proof maps it to the symmetric group and lets decide compare two permutations:
/-- **The free group on two generators is not abelian.** By van Kampen's theorem it is the
fundamental group of the figure eight `S¹ ∨ S¹` (not formalised here). To see `ab ≠ ba`, send
`a ↦ (0 1)` and `b ↦ (1 2)` in the symmetric group `S₃` (the universal property `FreeGroup.lift`):
the images of `ab` and `ba` are different permutations, which `decide` checks. -/
theorem free_group_not_comm :
FreeGroup.of (0 : Fin 2) * FreeGroup.of 1 ≠ FreeGroup.of 1 * FreeGroup.of 0 := by
intro h
let φ : FreeGroup (Fin 2) →* Equiv.Perm (Fin 3) :=
FreeGroup.lift (fun i => if i = 0 then Equiv.swap 0 1 else Equiv.swap 1 2)
have h' := congrArg φ h
simp only [map_mul, φ, FreeGroup.lift_apply_of] at h'
revert h'
decideWhat is and is not formalised. Independent: the straight-line homotopy and simple connectivity of vector spaces, functoriality, the no-retraction theorem, the one-dimensional Brouwer theorem and the non-commutativity of . Cited from Mathlib: the covering , path lifting, and change of basepoint. Not formalised: Corollary 7(b) and Corollary 8, the Seifert–van Kampen theorem (Mathlib has a categorical "van Kampen colimit" notion but not the topological theorem), the identification , and Theorem 10.
Lifting loops by computer, and counting coverings
Path lifting is an algorithm. Follow a sampled loop and, at each step, add the change of angle taken in . That is exactly the step-by-step construction in the proof of Theorem 5, with the samples playing the role of the subdivision. The total change divided by is the winding number; the program compares it with the contour integral , then watches a homotopy of circles and runs the argument of Corollary 8 on a cubic.
"""Winding numbers by path lifting, and what they can prove.
A loop in the punctured plane C minus {0} is lifted to the covering map
R -> circle by following its angle continuously: between two nearby samples
the angle changes by the representative of the difference in (-pi, pi].
The winding number is the total change divided by 2 pi. We compare it with
the contour integral (1 / 2 pi i) times the integral of dz / z, computed
separately by the midpoint rule. Then we watch a homotopy of circles: the
winding number stays constant until the circle passes through 0. Finally we
apply the idea to a cubic: the image of a large circle winds 3 times around
0 and the image of a small one 0 times, so the cubic must vanish somewhere
in between. Evidence: numerical (sampled loops), not proof.
"""
import cmath
import math
SAMPLES = 2000
def sample(loop, n=SAMPLES):
"""Points loop(k / n) for k = 0..n (the last equals the first)."""
return [loop(k / n) for k in range(n + 1)]
def lift_angles(points, centre=0j):
"""Continuous lift of the angle of points - centre (path lifting).
Raises ValueError if the loop passes through the centre.
"""
angles = []
for z in points:
w = z - centre
if abs(w) < 1e-12:
raise ValueError("the loop passes through the centre")
a = cmath.phase(w)
if angles:
step = (a - angles[-1] + math.pi) % (2 * math.pi) - math.pi
a = angles[-1] + step
angles.append(a)
return angles
def winding_number(points, centre=0j):
"""(final angle - initial angle) / 2 pi of the lifted loop."""
angles = lift_angles(points, centre)
return (angles[-1] - angles[0]) / (2 * math.pi)
def contour_integral(points, centre=0j):
"""(1 / 2 pi i) * integral of dz / (z - centre), by the midpoint rule."""
total = 0j
for z0, z1 in zip(points, points[1:]):
total += (z1 - z0) / ((z0 + z1) / 2 - centre)
return total / (2j * math.pi)
def circle(radius=1.0, centre=0j, turns=1):
"""The loop t -> centre + radius * exp(2 pi i turns t)."""
return lambda t: centre + radius * cmath.exp(2j * math.pi * turns * t)
def cubic(z):
"""p(z) = z^3 - 2z + 2, a cubic with no root on |z| = 1 or |z| = 2."""
return z ** 3 - 2 * z + 2
def main():
loops = [
("unit circle", circle()),
("circle, twice round", circle(turns=2)),
("circle, backwards", circle(turns=-1)),
("circle around 3", circle(1.0, 3 + 0j)),
("ellipse 3x by 0.5y", lambda t: complex(3 * math.cos(2 * math.pi * t),
0.5 * math.sin(2 * math.pi * t))),
]
print("Loop around 0 lift (turns) contour integral")
for name, loop in loops:
pts = sample(loop)
w, c = winding_number(pts), contour_integral(pts)
print(f" {name:<22} {w:10.6f} {c.real:9.6f} {c.imag:+.1e}i")
print()
print("Homotopy of circles: radius 1, centre s (crosses 0 at s = 1)")
row = []
for s in (0.0, 0.5, 0.9, 1.0, 1.1, 1.5):
try:
w = winding_number(sample(circle(1.0, complex(s, 0))))
row.append(f"s={s}: {round(w)}")
except ValueError:
row.append(f"s={s}: undefined")
print(" " + ", ".join(row))
print()
print("Images of circles |z| = R under p(z) = z^3 - 2z + 2:")
row = []
for radius in (0.5, 1.0, 1.5, 2.0, 10.0):
pts = [cubic(z) for z in sample(circle(radius))]
row.append(f"R={radius}: {round(winding_number(pts))}")
print(" " + ", ".join(row))
roots = sorted(abs(r) for r in (-1.7693, 0.8846 + 0.5897j))
print(f" (the roots have absolute values about {roots[0]:.3f} (twice) and")
print(f" {roots[1]:.3f}; by the argument principle the winding number")
print(" counts the roots inside the circle)")
print()
print("If p had no root, the loops p(R e^{2 pi i t}) would be homotopic in")
print("C minus {0} for all R, so they would all wind equally often. Winding")
print("0 times for small R and 3 times for large R forces a root.")
print()
print("Epistemic status: numerical. Each loop is sampled at 2000 points, and")
print("the lift is right only if consecutive samples turn by less than pi;")
print("the agreement with the contour integral is a consistency check, not")
print("a proof. The theorems behind it (pi_1(S^1) = Z and homotopy")
print("invariance) are proved in the lesson.")
if __name__ == "__main__":
main()This is numerical evidence: the lift is correct only if consecutive samples turn by less than — the computational shadow of the Lebesgue number in the proof.
The second program works in . It reduces words, detects with a homomorphism to (as the Lean proof does), and counts covering spaces of the figure eight by counting pairs of permutations.
"""The fundamental group of the figure eight, and its covering spaces.
By van Kampen's theorem the fundamental group of the figure eight (two
circles joined at a point) is the free group F2 on two loops a and b. We
compute with reduced words (A and B stand for the inverse loops), check that
ab and ba are different, and detect the difference with a homomorphism to
the symmetric group S3. Then we count covering spaces: an n-sheeted covering
of the figure eight is the same as a pair of permutations (where a and b
send each sheet), it is connected exactly when the pair acts transitively,
and connected coverings with a chosen base sheet correspond to subgroups of
index n in F2. Evidence: exact and exhaustive for the finite cases shown.
"""
from itertools import permutations, product
INVERSE = {"a": "A", "A": "a", "b": "B", "B": "b"}
def reduce_word(word):
"""Cancel adjacent inverse pairs (aA, Aa, bB, Bb) until none remain."""
out = []
for letter in word:
if out and out[-1] == INVERSE[letter]:
out.pop()
else:
out.append(letter)
return "".join(out)
def inverse_word(word):
"""The inverse of a word: reverse it and invert each letter."""
return "".join(INVERSE[c] for c in reversed(word))
def reduced_words(length):
"""All reduced words of the given length."""
return [w for w in map("".join, product("aAbB", repeat=length))
if reduce_word(w) == w]
def compose(p, q):
"""The permutation 'first p, then q' (tuples of images)."""
return tuple(q[p[i]] for i in range(len(p)))
def act(word, sigma, tau):
"""Image of a word under a -> sigma, b -> tau (letters act left to right)."""
n = len(sigma)
inv = {
"a": sigma, "b": tau,
"A": tuple(sorted(range(n), key=lambda i: sigma[i])),
"B": tuple(sorted(range(n), key=lambda i: tau[i])),
}
result = tuple(range(n))
for letter in word:
result = compose(result, inv[letter])
return result
def is_transitive(sigma, tau):
"""Whether the group generated by sigma and tau moves 0 to every point."""
seen, frontier = {0}, [0]
while frontier:
i = frontier.pop()
for j in (sigma[i], tau[i]):
if j not in seen:
seen.add(j)
frontier.append(j)
return len(seen) == len(sigma)
def transitive_pairs(n):
"""All transitive pairs (sigma, tau) of permutations of {0, ..., n-1}."""
perms = list(permutations(range(n)))
return [(s, t) for s in perms for t in perms if is_transitive(s, t)]
def subgroups_of_index(n):
"""Subgroups of index n in F2 = transitive pairs / (n - 1)!."""
count = len(transitive_pairs(n))
factorial = 1
for k in range(2, n):
factorial *= k
return count // factorial
def connected_covers(n):
"""Connected n-sheeted coverings up to isomorphism: transitive pairs up to
simultaneous relabelling of the sheets."""
perms = list(permutations(range(n)))
seen, classes = set(), 0
for s, t in transitive_pairs(n):
if (s, t) in seen:
continue
classes += 1
for g in perms:
g_inv = tuple(sorted(range(n), key=lambda i: g[i]))
seen.add((compose(compose(g_inv, s), g), compose(compose(g_inv, t), g)))
return classes
def main():
print("Words in F2 = pi_1(figure eight); A, B are the inverse loops.")
for word in ("abBA", "aAbaB", "ab", "ba", "abAB"):
shown = reduce_word(word) or "(empty word = constant loop)"
print(f" {word:<6} reduces to {shown}")
counts = [len(reduced_words(k)) for k in range(1, 7)]
print(f" reduced words of length 1..6: {counts} (4 * 3^(k-1))")
print()
sigma, tau = (1, 0, 2), (0, 2, 1)
print("Homomorphism to S3: a -> (0 1), b -> (1 2) as permutations of 0,1,2")
for word in ("ab", "ba", "abAB"):
print(f" {word:<5} -> {act(word, sigma, tau)}")
print(" ab and ba have different images, so ab != ba in F2: the")
print(" fundamental group of the figure eight is not abelian.")
print()
print("Coverings of the figure eight with n sheets:")
print(" n transitive pairs subgroups of index n connected covers")
for n in range(1, 6):
pairs = len(transitive_pairs(n))
covers = connected_covers(n) if n <= 4 else "-"
print(f" {n} {pairs:17d} {subgroups_of_index(n):21d} {covers:>17}")
print()
print("Epistemic status: exact and exhaustive for words of length at most 6")
print("and coverings with at most 5 sheets (the subgroup counts agree with")
print("Marshall Hall's 1949 formula). That pi_1 of the figure eight is F2,")
print("and that coverings match subgroups, are theorems quoted from the")
print("lesson, not consequences of this computation.")
if __name__ == "__main__":
main()The counts are exact for sheets. The numbers of subgroups of index in grow faster than exponentially, while has exactly one subgroup of each index. That is one numerical measure of how much bigger a free group is than the fundamental group of the circle.
Explore: winding numbers and universal covers
Drag the hole, choose a loop or draw your own, and press Play: the arrow from the hole to the moving point sweeps out the winding number, the degree of Theorem 6. The integral beside it is computed independently. Then add a second hole and try the figure-eight loop: it winds and around the two holes. Try to imagine the commutator loop : it winds times around each hole, yet it cannot be shrunk, because of the twice-punctured plane is the non-abelian group .
Loops around holes: the winding number
Follow a closed loop and count how many times it goes around each hole: counter-clockwise turns minus clockwise turns.
Drag a hole to move it. Press Play to send the point around the loop, or use the slider. The small square marks the start.
Winding number around p₁1
(1/2πi)∮ dz/(z − p₁) ≈ 1.000 + 0.000i
Turns swept so far by each dashed arrow:
p₁: 0.00
The winding number is found by adding up the small changes in direction of the arrow from the hole to the moving point, and dividing the total by 360°. Counter-clockwise counts as positive.
Two loops in the plane with one hole can be deformed into each other, without ever crossing the hole, exactly when they have the same winding number. In the language of topology: the fundamental group of the punctured plane — like that of a circle — is the integers, π₁ = ℤ.
A link to complex analysis: think of the plane as the complex numbers and of a hole as a point a. Then (1/2πi)∮ dz/(z − a) equals the winding number around a. The values above are computed numerically along the loop.
The torus is a square with opposite sides glued. Its universal cover is the plane, tiled by copies of the square; deck transformations are the translations by . Walk across a seam in the tiling view and compare with the flat square. For the Klein bottle, alternate columns are mirror images, and the deck group is a non-abelian group.
Universal covers: the plane above the torus
Glue the sides of a square in pairs so that the arrows match. Walk a flatlander across a side and watch where — and how — it comes back.
Keys: ↑ forward, ↓ back, ← and → turn, Space walks or stops. You can also drag it.
- Orientable
- Yes
- Euler characteristic
- χ = 0
Gluing turns the 4 corners into V = 1, the 4 sides into E = 2 and the square into F = 1: V − E + F = 1 − 2 + 1 = 0
Same way round as at the start.
Sides crossed so far: 0
Opposite sides are glued with arrows pointing the same way. Walk off the right side and you come back on the left, the same way round. However it walks, the flatlander is never mirrored: the torus is orientable.
Copies of the square tile the plane, and the trail runs on smoothly from copy to copy. This plane is the universal cover of the torus.
Exercises
1. Homotopy and the fundamental group
Warm-upHumanWhich of these spaces are simply connected? (Choose all that apply.)
2. Homotopy and the fundamental group
Warm-upHumanUnder the isomorphism of Theorem 6, what integer corresponds to the class of the loop ?
3. Homotopy and the fundamental group
CoreHumanIn the proof that the degree is well defined, we lift a path homotopy from to to , and then claim that is constant. Why is it constant?
4. Homotopy and the fundamental group
CoreHumanBrouwer's theorem says every continuous map has a fixed point. For which of these spaces is there a continuous map to itself with no fixed point? (Choose all that apply.)
5. Homotopy and the fundamental group
CoreHumanThe closed orientable surface of genus 2 is an octagon with sides glued by the word . What does the Seifert–van Kampen theorem give for its fundamental group?
6. Homotopy and the fundamental group
CoreFormalThe lesson's Lean theorem circle_not_retract takes a simply connected space X, maps i : C(AddCircle 1, X) and r : C(X, AddCircle 1), and a hypothesis h, and proves False. Which hypothesis h makes it the no-retraction theorem?
7. Homotopy and the fundamental group
CoreComputationalImplement path lifting for the angle. Write winding_number(points) for a list of non-zero complex numbers points describing a closed loop around (the last point equals the first). Add up the changes of angle between consecutive points, each taken in , and return the total divided by , rounded to the nearest integer.
8. Homotopy and the fundamental group
StretchHumanHow many connected 2-sheeted covering spaces does the figure eight have, up to isomorphism?
9. Homotopy and the fundamental group
StretchHumanIn the plane with two holes, let and be loops going once around the first and the second hole. True or false: the loop , which winds times around each hole, is null-homotopic.
Common misconceptions
Misconception
"Fundamental groups are always abelian." and are abelian, but is the free group , in which ; the surface groups of genus are non-abelian too. (The fundamental group of a topological group is abelian — an Eckmann–Hilton argument.)
Misconception
"Spaces with isomorphic fundamental groups are homeomorphic." , and a point all have trivial ; , the annulus and the solid torus all have . The fundamental group only sees the space up to homotopy, and even then only its "one-dimensional" part. The Poincaré conjecture, proved by Grigori Perelman in 2002–2003, says that among closed 3-manifolds, does force — a deep theorem about one special situation.
Misconception
"A loop that winds zero times around every hole can be shrunk." In the plane with two holes, the commutator of the loops , around them winds zero times around each hole but is not null-homotopic, since in . Winding numbers only see the abelianisation of .
Misconception
"Homotopic loops are the same as freely homotopic loops." In the basepoint must stay fixed during the homotopy. If the basepoint may move, loops are classified by the conjugacy classes of instead. For abelian groups like there is no difference; in , the loops and are freely homotopic but not homotopic rel basepoint.
Misconception
"A deformation may pass through the hole if it comes out the other side." A homotopy is a map into at every moment. A loop around the origin of cannot be dragged across the origin, even briefly — that is exactly what the first experiment shows when the circle's centre crosses .
Many ways of seeing
Topology— The first of the homotopy groups
is the first of the homotopy groups , built from maps of spheres ; for they are abelian. They are hard to compute: (Hopf, 1931), and the homotopy groups of spheres are still not fully known. Homology is easier and coarser. The Hurewicz theorem says that is the abelianisation of for path-connected , which is why winding numbers, which are homological, cannot see the commutator loop. The Poincaré conjecture, now Perelman's theorem, shows how much can know: a closed 3-manifold with trivial is homeomorphic to . See algebraic topology and low-dimensional topology.
Algebra— Every group is a fundamental group; Galois theory and coverings
Every group is the fundamental group of some space. Given a presentation , take a wedge of circles, one for each generator, and glue in a disc along each relator; by van Kampen the resulting 2-complex has . So questions about groups become questions about spaces. Geometric group theory grew out of this, and Max Dehn's word problem for surface groups (1911) was an early example.
Theorem 10 has the same shape as the fundamental theorem of Galois theory. Intermediate coverings correspond to subgroups of the deck group, just as intermediate fields correspond to subgroups of the Galois group; normal subgroups give regular coverings and Galois extensions. This is more than an analogy. Grothendieck's étale fundamental group treats both at once: for a field it is the absolute Galois group of , and for a complex algebraic variety it is the profinite completion of the topological .
Analysis— Winding numbers as integrals
For a loop in the degree is an integral: . Homotopy invariance of the integral is Cauchy's theorem, and counting zeros with it is the argument principle of complex analysis, which the first experiment uses. More generally, a closed differential 1-form on defines a homomorphism , , well defined by Stokes' theorem. The form on the punctured plane gives times the winding number, and is closed but not exact. That is the starting point of de Rham cohomology in differential forms and Stokes' theorem.
Geometry— The group seen from far away
A closed surface of genus carries a metric of constant curvature , and its universal cover is the hyperbolic plane, tiled by -gons on which acts by isometries (the genus-1 analogue is the flat torus covered by the Euclidean plane). The Švarc–Milnor lemma says that if a group acts properly and cocompactly by isometries on a geodesic metric space, the group — with its word metric — looks like that space from far away (they are quasi-isometric). So the fundamental group of a compact Riemannian manifold "is" the large-scale geometry of its universal cover. Surface groups of genus at least 2 are hyperbolic groups, and is flat. See geometric group theory.
Physics— Phases, spin and anyons
In the Aharonov–Bohm effect (1959) an electron passing around a thin solenoid acquires a phase proportional to the enclosed magnetic flux, although the magnetic field vanishes along its path. The phase depends only on the homotopy class of the path in the plane minus the solenoid — a winding number. The rotation group has , with the double cover . This is the mathematics behind spin-½ particles, whose state changes sign under a rotation, and behind the "belt trick": a twist of a belt with fixed ends can be undone, a twist cannot. In two spatial dimensions, the configuration space of identical particles has the braid group as , which permits anyons with exotic exchange statistics. These are physical models whose consistency rests on the topology; the topology itself is proved, not assumed from physics.
Category theory— The fundamental groupoid
Instead of fixing a basepoint, take all points as objects and homotopy classes of paths as arrows: the fundamental groupoid , a category in which every arrow is invertible. is the automorphism group of one object — that is literally Mathlib's definition — and Proposition 3 says that objects in the same connected component have isomorphic automorphism groups. A map induces a functor , and Proposition 4 says homotopic maps give naturally isomorphic functors. Groupoids also give the cleanest van Kampen theorem (Ronald Brown's version for groupoids applies with non-connected intersections, so it computes itself). In homotopy type theory the circle is a higher inductive type, and has a synthetic proof (Licata and Shulman, 2013).
Computation— What cannot be computed
Given a finite presentation of a group, can a computer decide whether a word equals ? For free groups, surface groups and many others, yes: reduce the word (Dehn's algorithm). In general, no. Pyotr Novikov (1955) and William Boone (1958) constructed finitely presented groups with undecidable word problem. Since every finitely presented group is the fundamental group of a closed 4-manifold, Andrei Markov Jr. (1958) deduced that there is no algorithm to decide whether two 4-manifolds, given by triangulations, are homeomorphic. Topology inherits the limits of computation through .
History and global context
- Winding numbers before topology. Augustin-Louis Cauchy's integral theorem (1825) and his residue calculus counted how curves wind around singular points. Bernhard Riemann's surfaces for multivalued functions (1851, 1857) were in effect covering spaces of the plane. Carl Friedrich Gauss's first proof of the fundamental theorem of algebra (1799) used a topological argument with a gap that Alexander Ostrowski closed in 1920.
- Poincaré. Henri Poincaré's Analysis Situs (1895) and its supplements introduced the fundamental group and homology, computed examples, and posed in 1904 the question that became the Poincaré conjecture. Grigori Perelman proved it in 2002–2003, building on Richard Hamilton's Ricci flow.
- Fixed points. Piers Bohl proved a result equivalent to the fixed-point theorem in 1904, Jacques Hadamard gave a proof in 1910, and L. E. J. Brouwer proved the general -dimensional theorem around 1910–1912.
- Groups from spaces, spaces from groups. Max Dehn (1910–1912) studied fundamental groups of surfaces and knot complements and posed the word, conjugacy and isomorphism problems. Herbert Seifert (1931) and Egbert van Kampen (1933) proved the gluing theorem. Pyotr Novikov in Moscow and William Boone in the United States showed in the 1950s that the word problem is undecidable in general.
- Covering spaces were systematised in the 1930s and 1940s (Seifert and Threlfall's 1934 textbook was influential), and Alexander Grothendieck's SGA 1 (1960–61) unified covering spaces and Galois theory in the étale fundamental group.
Further reading
- Allen Hatcher, Algebraic Topology (2002), chapter 1 — the standard modern account of , van Kampen and covering spaces (freely available from the author).
- James R. Munkres, Topology (2nd edition, 2000), chapters 9–14.
- William S. Massey, A Basic Course in Algebraic Topology (1991).
- William Fulton, Algebraic Topology: A First Course (1995) — emphasises winding numbers, integrals and complex analysis.
- John Stillwell, Classical Topology and Combinatorial Group Theory (2nd edition, 1993) — the interplay of surfaces, knots and presentations, with history.