Skip to content
The Lumenary
Advanced undergraduateUndergraduate 120 min

Homotopy and the fundamental group

Loops you cannot shrink form a group. Computing it for the circle — π1(S1)≅Z\pi_1(S^1) \cong \Z — proves Brouwer's fixed-point theorem and the fundamental theorem of algebra, and turns topology into algebra.

Formally verified · 15 LeanComputationally tested · 2 PythonAI-drafted · awaiting human reviewMathematically reviewed: Awaiting human review
MotivationH

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 R\R from R2\R^2 by removing a point and counting the pieces. It could not tell R2\R^2 from R3\R^3: both stay connected when a point is removed. What differs is the loops. In R2∖{0}\R^2 \setminus \{0\} a loop around the origin cannot be shrunk to a point; in R3∖{0}\R^3 \setminus \{0\} 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 π1\pi_1, whose elements are loops up to continuous deformation. This lesson builds that group, computes it for the circle, and uses it.

IntuitionH

Deforming loops

Take the plane with a hole at the origin, and loops that start and end at a basepoint x0=(1,0)x_0 = (1, 0). 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 γ\gamma, then δ\delta. Winding numbers add. Every loop has an inverse, the same loop run backwards, and γ\gamma 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 Z\Z. 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.

ℝS¹p
The covering map p : ℝ → S¹, drawn as a helix above a circle; p projects straight down. The points above the basepoint (dots) form a copy of ℤ. A loop in the circle lifts to a path on the helix, which ends on the floor where its winding number says.
DefinitionsH

Homotopy, paths and the fundamental group

Throughout, I=[0,1]I = [0, 1] and all maps are continuous.

Definition— homotopy

A homotopy between maps f,g:X→Yf, g : X \to Y is a map F:X×I→YF : X \times I \to Y with F(x,0)=f(x)F(x, 0) = f(x) and F(x,1)=g(x)F(x, 1) = g(x); then f≃gf \simeq g. A map is null-homotopic if it is homotopic to a constant map. A homotopy equivalence is a map f:X→Yf : X \to Y with a map g:Y→Xg : Y \to X such that g∘f≃idXg \circ f \simeq \mathrm{id}_X and f∘g≃idYf \circ g \simeq \mathrm{id}_Y. A space is contractible if it is homotopy equivalent to a point.

Definition— paths and path homotopy

A path from x0x_0 to x1x_1 is a map γ:I→X\gamma : I \to X with γ(0)=x0\gamma(0) = x_0 and γ(1)=x1\gamma(1) = x_1; a loop at x0x_0 is a path from x0x_0 to x0x_0. Two paths γ,δ\gamma, \delta from x0x_0 to x1x_1 are path-homotopic, γ≃δ\gamma \simeq \delta, if there is a homotopy F:I×I→XF : I \times I \to X with

F(s,0)=γ(s),F(s,1)=δ(s),F(0,t)=x0,F(1,t)=x1.F(s, 0) = \gamma(s), \quad F(s, 1) = \delta(s), \quad F(0, t) = x_0, \quad F(1, t) = x_1 .

So the endpoints stay fixed throughout. Write [γ][\gamma] for the path-homotopy class of γ\gamma.

Definition— concatenation and reverse

If γ\gamma ends where δ\delta begins, the concatenation γ⋅δ\gamma \cdot \delta runs γ\gamma at double speed, then δ\delta:

(γ⋅δ)(s)={γ(2s)0≤s≤12,δ(2s−1)12≤s≤1.(\gamma \cdot \delta)(s) = \begin{cases} \gamma(2s) & 0 \le s \le \tfrac12, \\ \delta(2s - 1) & \tfrac12 \le s \le 1. \end{cases}

It is continuous by the pasting lemma. The reverse of γ\gamma is γˉ(s)=γ(1−s)\bar\gamma(s) = \gamma(1 - s), and cxc_{x} denotes the constant path at xx.

Definition— fundamental group

The fundamental group π1(X,x0)\pi_1(X, x_0) is the set of path-homotopy classes of loops at x0x_0, with the product [γ][δ]=[γ⋅δ][\gamma][\delta] = [\gamma \cdot \delta]. A map f:X→Yf : X \to Y induces f∗:π1(X,x0)→π1(Y,f(x0))f_* : \pi_1(X, x_0) \to \pi_1(Y, f(x_0)), f∗[γ]=[f∘γ]f_*[\gamma] = [f \circ \gamma]. A path-connected space with trivial fundamental group is simply connected.

Definition— covering map

A map p:E→Bp : E \to B is a covering map if every b∈Bb \in B has an open neighbourhood UU that is evenly covered: p−1(U)p^{-1}(U) is a disjoint union of open sets (the sheets over UU), each mapped homeomorphically onto UU by pp. A lift of a map f:Z→Bf : Z \to B is a map f~:Z→E\tilde f : Z \to E with p∘f~=fp \circ \tilde f = f.

Example— The basic covering

p:R→S1⊆Cp : \R \to S^1 \subseteq \C, p(x)=e2πixp(x) = e^{2\pi i x}, is a covering map. For b=e2πiθb = e^{2\pi i \theta}, the open arc UU of points e2πixe^{2\pi i x} with ∣x−θ∣<1/2|x - \theta| < 1/2 is evenly covered: p−1(U)p^{-1}(U) is the disjoint union of the intervals (θ+n−12,θ+n+12)(\theta + n - \tfrac12, \theta + n + \tfrac12), n∈Zn \in \Z. So is z↦znz \mapsto z^n from S1S^1 to itself, for n≠0n \ne 0: every point has ∣n∣|n| preimages, and small arcs are evenly covered.

Worked examplesH

A first gallery

The theorems below justify every entry of this table.

Spaceπ1\pi_1Reason
Rn\R^n, a convex set, a disctrivialstraight-line homotopy (Example below)
circle S1S^1, punctured plane, annulusZ\ZTheorem 6 (and homotopy equivalence)
torus S1×S1S^1 \times S^1Z×Z\Z \times \Zproduct formula; also van Kampen
figure eight S1∨S1S^1 \vee S^1free group F2F_2 on two generatorsvan Kampen (Theorem 9)
sphere SnS^n, n≥2n \ge 2trivialvan Kampen
real projective plane RP2\R P^2Z/2\Z/2van Kampen, or the double cover S2→RP2S^2 \to \R P^2
closed orientable surface of genus gg⟨a1,b1,…,ag,bg∣[a1,b1]⋯[ag,bg]⟩\langle a_1, b_1, \dots, a_g, b_g \mid [a_1, b_1] \cdots [a_g, b_g] \ranglevan Kampen

Example— Convex sets are simply connected

If C⊆RnC \subseteq \R^n is convex and γ,δ\gamma, \delta are paths in CC from x0x_0 to x1x_1, then F(s,t)=(1−t)γ(s)+tδ(s)F(s, t) = (1 - t)\gamma(s) + t\delta(s) stays in CC (by convexity), is continuous, equals γ\gamma at t=0t = 0 and δ\delta at t=1t = 1, and keeps the endpoints fixed because (1−t)x0+tx0=x0(1 - t)x_0 + t x_0 = x_0. 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 X×YX \times Y is a pair of loops, and a path homotopy is a pair of path homotopies, so π1(X×Y,(x0,y0))≅π1(X,x0)×π1(Y,y0)\pi_1(X \times Y, (x_0, y_0)) \cong \pi_1(X, x_0) \times \pi_1(Y, y_0). For the torus this gives Z×Z\Z \times \Z: 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

S2S^2 and a single point both have trivial fundamental group, but they are not homeomorphic (and not even homotopy equivalent: S2S^2 has a non-trivial second homotopy group). The fundamental group is an invariant, not a complete classification.

ProofH

The fundamental group is a group, and an invariant

Theorem— Lemma 1 (reparametrisation)

If φ:I→I\varphi : I \to I is continuous with φ(0)=0\varphi(0) = 0 and φ(1)=1\varphi(1) = 1, then γ∘φ≃γ\gamma \circ \varphi \simeq \gamma for every path γ\gamma.

Proof

F(s,t)=γ((1−t)φ(s)+ts)F(s, t) = \gamma\big((1 - t)\varphi(s) + ts\big) is defined because II is convex, it is continuous, it equals γ∘φ\gamma \circ \varphi at t=0t = 0 and γ\gamma at t=1t = 1, and F(0,t)=γ(0)F(0, t) = \gamma(0), F(1,t)=γ(1)F(1, t) = \gamma(1).

∎

Theorem— Theorem 2 (π₁ is a group)

Path homotopy is an equivalence relation, concatenation is well defined on classes, and π1(X,x0)\pi_1(X, x_0) is a group with identity [cx0][c_{x_0}] and inverses [γ]−1=[γˉ][\gamma]^{-1} = [\bar\gamma].

Proof

Equivalence relation. Reflexivity: F(s,t)=γ(s)F(s, t) = \gamma(s). Symmetry: F(s,1−t)F(s, 1 - t). Transitivity: run a homotopy from γ\gamma to δ\delta for t∈[0,12]t \in [0, \tfrac12] and one from δ\delta to ε\varepsilon for t∈[12,1]t \in [\tfrac12, 1], at double speed.

Well defined. If FF is a path homotopy from γ\gamma to γ′\gamma' and GG from δ\delta to δ′\delta', then placing FF on [0,12]×I[0, \tfrac12] \times I and GG on [12,1]×I[\tfrac12, 1] \times I (with ss rescaled) gives a path homotopy from γ⋅δ\gamma \cdot \delta to γ′⋅δ′\gamma' \cdot \delta'; the pieces agree on s=12s = \tfrac12, where both equal the common endpoint.

Associativity. (γ⋅δ)⋅ε(\gamma \cdot \delta) \cdot \varepsilon runs γ,δ,ε\gamma, \delta, \varepsilon on [0,14],[14,12],[12,1][0, \tfrac14], [\tfrac14, \tfrac12], [\tfrac12, 1], while γ⋅(δ⋅ε)\gamma \cdot (\delta \cdot \varepsilon) uses [0,12],[12,34],[34,1][0, \tfrac12], [\tfrac12, \tfrac34], [\tfrac34, 1]. So (γ⋅δ)⋅ε=(γ⋅(δ⋅ε))∘φ(\gamma \cdot \delta) \cdot \varepsilon = (\gamma \cdot (\delta \cdot \varepsilon)) \circ \varphi, where φ\varphi is piecewise linear, mapping [0,14]→[0,12][0, \tfrac14] \to [0, \tfrac12], [14,12]→[12,34][\tfrac14, \tfrac12] \to [\tfrac12, \tfrac34] and [12,1]→[34,1][\tfrac12, 1] \to [\tfrac34, 1]. Apply Lemma 1.

Identity. cx0⋅γ=γ∘φc_{x_0} \cdot \gamma = \gamma \circ \varphi with φ(s)=max⁡(0,2s−1)\varphi(s) = \max(0, 2s - 1), and similarly for γ⋅cx0\gamma \cdot c_{x_0}. Apply Lemma 1.

Inverses. F(s,t)=γ(2s(1−t))F(s, t) = \gamma\big(2s(1 - t)\big) for s≤12s \le \tfrac12 and F(s,t)=γ((2−2s)(1−t))F(s, t) = \gamma\big((2 - 2s)(1 - t)\big) for s≥12s \ge \tfrac12 agree at s=12s = \tfrac12, equal γ⋅γˉ\gamma \cdot \bar\gamma at t=0t = 0 and the constant loop at t=1t = 1, and fix both ends at x0x_0. So γ⋅γˉ≃cx0\gamma \cdot \bar\gamma \simeq c_{x_0}, and likewise γˉ⋅γ≃cx0\bar\gamma \cdot \gamma \simeq c_{x_0}.

∎

Theorem— Proposition 3 (basepoints)

A path hh from x0x_0 to x1x_1 gives an isomorphism βh:π1(X,x0)→π1(X,x1)\beta_h : \pi_1(X, x_0) \to \pi_1(X, x_1), βh[γ]=[hˉ⋅γ⋅h]\beta_h[\gamma] = [\bar h \cdot \gamma \cdot h]. So for path-connected XX the group π1(X,x0)\pi_1(X, x_0) does not depend on x0x_0, up to isomorphism.

Proof

βh[γ] βh[δ]=[hˉ⋅γ⋅h⋅hˉ⋅δ⋅h]=[hˉ⋅γ⋅δ⋅h]=βh([γ][δ])\beta_h[\gamma] \, \beta_h[\delta] = [\bar h \cdot \gamma \cdot h \cdot \bar h \cdot \delta \cdot h] = [\bar h \cdot \gamma \cdot \delta \cdot h] = \beta_h([\gamma][\delta]), using h⋅hˉ≃cx0h \cdot \bar h \simeq c_{x_0} and the group laws of Theorem 2 (which hold for paths, not only loops, with the same proofs). The inverse of βh\beta_h is βhˉ\beta_{\bar h}.

∎

The isomorphism βh\beta_h depends on the homotopy class of hh: changing hh composes βh\beta_h with conjugation by a loop. So when π1\pi_1 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) f∗f_* is a homomorphism, (g∘f)∗=g∗∘f∗(g \circ f)_* = g_* \circ f_* and (idX)∗=id(\mathrm{id}_X)_* = \mathrm{id}. (b) If F:X×I→YF : X \times I \to Y is a homotopy from ff to gg with F(x0,t)=y0F(x_0, t) = y_0 for all tt, then f∗=g∗f_* = g_*. (c) A homotopy equivalence f:X→Yf : X \to Y induces an isomorphism π1(X,x0)≅π1(Y,f(x0))\pi_1(X, x_0) \cong \pi_1(Y, f(x_0)).

Proof

(a) f∘(γ⋅δ)=(f∘γ)⋅(f∘δ)f \circ (\gamma \cdot \delta) = (f \circ \gamma) \cdot (f \circ \delta), and ff carries path homotopies to path homotopies. The other two equations hold already on loops.

(b) For a loop γ\gamma at x0x_0, (s,t)↦F(γ(s),t)(s, t) \mapsto F(\gamma(s), t) is a path homotopy from f∘γf \circ \gamma to g∘γg \circ \gamma; its ends stay at F(x0,t)=y0F(x_0, t) = y_0.

(c) When a homotopy FF from ff to gg does not fix the basepoint, one shows instead that g∗=βh∘f∗g_* = \beta_h \circ f_*, where h(t)=F(x0,t)h(t) = F(x_0, t) is the track of the basepoint; see Hatcher (2002), Lemma 1.19. Now let gg be a homotopy inverse of ff. Applying this to g∘f≃idXg \circ f \simeq \mathrm{id}_X shows that g∗∘f∗g_* \circ f_* is a change-of-basepoint isomorphism, so g∗:π1(Y,f(x0))→π1(X,gf(x0))g_* : \pi_1(Y, f(x_0)) \to \pi_1(X, g f(x_0)) is surjective. Applying it to f∘g≃idYf \circ g \simeq \mathrm{id}_Y shows that f∗∘g∗f_* \circ g_* is an isomorphism, so the same g∗g_* is injective. Hence g∗g_* is an isomorphism, and so is f∗=g∗−1∘(g∗∘f∗)f_* = g_*^{-1} \circ (g_* \circ f_*).

∎

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.

ProofH

Lifting, and the fundamental group of the circle

Theorem— Theorem 5 (path and homotopy lifting)

Let p:E→Bp : E \to B be a covering map. (a) For every path γ\gamma in BB and every e∈p−1(γ(0))e \in p^{-1}(\gamma(0)) there is a unique lift γ~\tilde\gamma with γ~(0)=e\tilde\gamma(0) = e. (b) For every map F:I×I→BF : I \times I \to B and every e∈p−1(F(0,0))e \in p^{-1}(F(0, 0)) there is a unique lift F~\tilde F with F~(0,0)=e\tilde F(0, 0) = e. If FF is a path homotopy, so is F~\tilde F.

Proof

(a) Existence. The sets γ−1(U)\gamma^{-1}(U), for UU evenly covered, form an open cover of the compact metric space II. By the Lebesgue number lemma there is a subdivision 0=s0<s1<⋯<sm=10 = s_0 < s_1 < \dots < s_m = 1 such that each γ([sk−1,sk])\gamma([s_{k-1}, s_k]) lies in one evenly covered set UkU_k. Suppose γ~\tilde\gamma is defined on [0,sk−1][0, s_{k-1}]. Let U~\tilde U be the sheet over UkU_k that contains γ~(sk−1)\tilde\gamma(s_{k-1}), and set γ~=(p∣U~)−1∘γ\tilde\gamma = (p|_{\tilde U})^{-1} \circ \gamma on [sk−1,sk][s_{k-1}, s_k]. The two definitions agree at sk−1s_{k-1}, so the pasting lemma keeps γ~\tilde\gamma continuous. After mm steps, γ~\tilde\gamma is defined on II.

Uniqueness. Let γ~,γ^\tilde\gamma, \hat\gamma be lifts with the same start, and A={s∣γ~(s)=γ^(s)}A = \{s \mid \tilde\gamma(s) = \hat\gamma(s)\}, which contains 00. Given ss, choose an evenly covered U∋γ(s)U \ni \gamma(s) and the sheets U~∋γ~(s)\tilde U \ni \tilde\gamma(s), U^∋γ^(s)\hat U \ni \hat\gamma(s). On a small interval JJ around ss, both lifts stay in their sheets. If U~=U^\tilde U = \hat U, both equal (p∣U~)−1∘γ(p|_{\tilde U})^{-1} \circ \gamma on JJ, so J⊆AJ \subseteq A. If U~≠U^\tilde U \ne \hat U the sheets are disjoint, so J∩A=∅J \cap A = \varnothing. Hence AA and its complement are open; II is connected, so A=IA = I.

(b) The same argument on the square: subdivide I×II \times I 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 s↦(s,t)s \mapsto (s, t) and t↦(0,t)t \mapsto (0, t). If FF is a path homotopy, then t↦F(0,t)t \mapsto F(0, t) and t↦F(1,t)t \mapsto F(1, t) 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)

π1(S1,1)≅Z\pi_1(S^1, 1) \cong \Z. The isomorphism sends the class of a loop γ\gamma to its degree: γ~(1)\tilde\gamma(1), where γ~\tilde\gamma is the lift of γ\gamma to R\R with γ~(0)=0\tilde\gamma(0) = 0 under p(x)=e2πixp(x) = e^{2\pi i x}.

Proof

The lift ends in p−1(1)=Zp^{-1}(1) = \Z, so deg⁡γ=γ~(1)\deg \gamma = \tilde\gamma(1) is an integer.

Well defined. If FF is a path homotopy from γ\gamma to γ′\gamma', lift it with F~(0,0)=0\tilde F(0, 0) = 0 (Theorem 5b). By uniqueness, F~(⋅,0)=γ~\tilde F(\cdot, 0) = \tilde\gamma and F~(⋅,1)=γ~′\tilde F(\cdot, 1) = \tilde\gamma'. The path t↦F~(1,t)t \mapsto \tilde F(1, t) lifts the constant path at 11, so it lies in the discrete set Z\Z; a path in a discrete space is constant. Hence γ~(1)=γ~′(1)\tilde\gamma(1) = \tilde\gamma'(1).

Homomorphism. Let γ~\tilde\gamma lift γ\gamma from 00 to mm and δ~\tilde\delta lift δ\delta from 00 to nn. The translate δ~+m\tilde\delta + m also lifts δ\delta (as p(x+m)=p(x)p(x + m) = p(x)), from mm to m+nm + n. So γ~⋅(δ~+m)\tilde\gamma \cdot (\tilde\delta + m) lifts γ⋅δ\gamma \cdot \delta from 00 to m+nm + n: deg⁡(γ⋅δ)=deg⁡γ+deg⁡δ\deg(\gamma \cdot \delta) = \deg \gamma + \deg \delta.

Surjective. The loop ωn(s)=e2πins\omega_n(s) = e^{2\pi i n s} lifts to s↦nss \mapsto ns, so it has degree nn.

Injective. If deg⁡γ=0\deg \gamma = 0, then γ~\tilde\gamma is a loop at 00 in R\R, and F~(s,t)=(1−t)γ~(s)\tilde F(s, t) = (1 - t)\tilde\gamma(s) is a path homotopy from γ~\tilde\gamma to the constant loop. Then p∘F~p \circ \tilde F is a path homotopy from γ\gamma to the constant loop.

∎

The same proof, with the covering C→C∖{0}\C \to \C \setminus \{0\}, z↦ezz \mapsto e^z, shows that π1(C∖{0})≅Z\pi_1(\C \setminus \{0\}) \cong \Z, with the winding number as the isomorphism.

ProofH

Brouwer and the fundamental theorem of algebra

Theorem— Corollary 7 (no retraction; Brouwer's fixed-point theorem)

(a) There is no map r:D2→S1r : D^2 \to S^1 with r(x)=xr(x) = x for all x∈S1x \in S^1. (b) Every map f:D2→D2f : D^2 \to D^2 of the closed disc to itself has a fixed point.

Proof

(a) Let i:S1→D2i : S^1 \to D^2 be the inclusion. If r∘i=idS1r \circ i = \mathrm{id}_{S^1}, then r∗∘i∗=idr_* \circ i_* = \mathrm{id} on π1(S1)≅Z\pi_1(S^1) \cong \Z (Proposition 4a). But i∗i_* lands in π1(D2)\pi_1(D^2), which is trivial (the disc is convex). So the identity of Z\Z would factor through the trivial group, which is absurd.

(b) Suppose f(x)≠xf(x) \ne x for every xx. Let r(x)r(x) be the point where the ray from f(x)f(x) through xx leaves the disc. Explicitly, with u=x−f(x)≠0u = x - f(x) \ne 0, r(x)=x+τur(x) = x + \tau u, where τ≥0\tau \ge 0 solves ∣x+τu∣2=1|x + \tau u|^2 = 1:

τ=−⟨x,u⟩+⟨x,u⟩2+∣u∣2(1−∣x∣2)∣u∣2.\tau = \frac{-\langle x, u\rangle + \sqrt{\langle x, u\rangle^2 + |u|^2 (1 - |x|^2)}}{|u|^2}.

The square root is of a non-negative continuous function (as ∣x∣≤1|x| \le 1), so rr is continuous. If ∣x∣=1|x| = 1, then ⟨x,u⟩=1−⟨x,f(x)⟩≥0\langle x, u\rangle = 1 - \langle x, f(x)\rangle \ge 0 (Cauchy–Schwarz and ∣f(x)∣≤1|f(x)| \le 1), so τ=0\tau = 0 and r(x)=xr(x) = x. Thus rr is a retraction of D2D^2 onto S1S^1, contradicting (a).

∎

The same theorem holds for the closed ball DnD^n in every dimension, with π1\pi_1 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 x↦(x+e1)/2x \mapsto (x + e_1)/2 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 p(z)=zn+an−1zn−1+⋯+a0p(z) = z^n + a_{n-1} z^{n-1} + \dots + a_0 with n≥1n \ge 1. Suppose pp has no root. For r≥0r \ge 0 define the loop

fr(s)=p(re2πis)/∣p(re2πis)∣p(r)/∣p(r)∣f_r(s) = \frac{p(r e^{2\pi i s}) / |p(r e^{2\pi i s})|}{p(r) / |p(r)|}

in S1S^1 at 11. As rr varies, (s,r)↦fr(s)(s, r) \mapsto f_r(s) is a path homotopy between any two of these loops, and f0f_0 is constant. So [fr]=0[f_r] = 0 in π1(S1)\pi_1(S^1) for all rr.

Now fix R>max⁡(1,∣a0∣+⋯+∣an−1∣)R > \max(1, |a_0| + \dots + |a_{n-1}|). For ∣z∣=R|z| = R,

∣an−1zn−1+⋯+a0∣≤(∣an−1∣+⋯+∣a0∣)Rn−1<Rn=∣zn∣,|a_{n-1} z^{n-1} + \dots + a_0| \le (|a_{n-1}| + \dots + |a_0|) R^{n-1} < R^n = |z^n|,

so pt(z)=zn+t(an−1zn−1+⋯+a0)p_t(z) = z^n + t(a_{n-1} z^{n-1} + \dots + a_0) has no zero on ∣z∣=R|z| = R for t∈[0,1]t \in [0, 1]. Replacing pp by ptp_t in the formula for fRf_R gives a path homotopy from fRf_R (at t=1t = 1) to s↦e2πinss \mapsto e^{2\pi i n s} (at t=0t = 0), whose degree is n≠0n \ne 0. This contradicts [fR]=0[f_R] = 0.

∎

ProofH

Gluing spaces: van Kampen, and covering spaces

To compute π1\pi_1 of a space built from simpler pieces, one glues the groups.

Theorem— Theorem 9 (Seifert–van Kampen; stated, proof referenced)

Let X=U∪VX = U \cup V with U,VU, V open and path-connected, U∩VU \cap V path-connected, and x0∈U∩Vx_0 \in U \cap V. Then the inclusions induce an isomorphism

π1(X,x0)≅π1(U,x0)∗π1(U∩V,x0)π1(V,x0),\pi_1(X, x_0) \cong \pi_1(U, x_0) *_{\pi_1(U \cap V, x_0)} \pi_1(V, x_0),

the free product of π1(U)\pi_1(U) and π1(V)\pi_1(V) modulo the relations iU(ω)=iV(ω)i_U(\omega) = i_V(\omega) for ω∈π1(U∩V)\omega \in \pi_1(U \cap V).

The proof subdivides a loop, or a homotopy, into pieces lying in UU or in VV by the Lebesgue number lemma; see Hatcher (2002), Theorem 1.20. In practice it is used like this:

  • Wedge of circles. For S1∨S1S^1 \vee S^1, take UU and VV to be each circle together with a short open arc of the other at the wedge point. Each deformation retracts to a circle and U∩VU \cap V is contractible, so π1(S1∨S1)≅Z∗Z=F2\pi_1(S^1 \vee S^1) \cong \Z * \Z = F_2, the free group on two generators a,ba, b: its elements are reduced words such as ab2a−1ba b^2 a^{-1} b. In particular ab≠baab \ne ba, so fundamental groups need not be abelian.
  • Spheres. For SnS^n, n≥2n \ge 2, take UU and VV to be the complements of the north and south poles. Each is homeomorphic to Rn\R^n, and U∩V≅Sn−1×RU \cap V \cong S^{n-1} \times \R is path-connected when n≥2n \ge 2. So π1(Sn)\pi_1(S^n) is trivial. (For n=1n = 1 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 aba−1b−1a b a^{-1} b^{-1}. Take UU to be the open square and VV a neighbourhood of the glued boundary, which deformation retracts onto the figure eight a∪ba \cup b. Then U∩VU \cap V is an annulus, whose generator goes once around the boundary of the square, i.e. maps to aba−1b−1a b a^{-1} b^{-1} in π1(V)\pi_1(V). So π1(T2)=⟨a,b∣aba−1b−1⟩≅Z2\pi_1(T^2) = \langle a, b \mid a b a^{-1} b^{-1} \rangle \cong \Z^2. The genus-gg surface, a 4g4g-gon glued by [a1,b1]⋯[ag,bg][a_1, b_1] \cdots [a_g, b_g], has π1=⟨a1,…,bg∣[a1,b1]⋯[ag,bg]⟩\pi_1 = \langle a_1, \dots, b_g \mid [a_1, b_1] \cdots [a_g, b_g] \rangle, whose abelianisation is Z2g\Z^{2g}. Different genera give different groups, so the surfaces are pairwise non-homeomorphic. The projective plane, a disc with antipodal boundary points glued (word aaaa), has π1=⟨a∣a2⟩≅Z/2\pi_1 = \langle a \mid a^2 \rangle \cong \Z/2.

Covering spaces turn π1\pi_1 into a Galois-like correspondence.

Theorem— Theorem 10 (classification of covering spaces; stated, proof referenced)

Let BB be path-connected, locally path-connected and semilocally simply connected, with basepoint b0b_0. Then (E,e0)↦p∗π1(E,e0)(E, e_0) \mapsto p_*\pi_1(E, e_0) is a bijection from isomorphism classes of connected based covering spaces p:(E,e0)→(B,b0)p : (E, e_0) \to (B, b_0) onto subgroups of π1(B,b0)\pi_1(B, b_0). 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 B~\tilde B, whose group of deck transformations is isomorphic to π1(B,b0)\pi_1(B, b_0).

The proof (Hatcher 2002, Theorem 1.38) constructs B~\tilde B as the space of homotopy classes of paths starting at b0b_0 and obtains the other coverings as its quotients. Examples: the coverings of S1S^1 are R→S1\R \to S^1 (subgroup 00) and z↦znz \mapsto z^n (subgroup nZn\Z); the universal cover of the torus is the plane, with deck group Z2\Z^2 acting by translations. An nn-sheeted covering of the figure eight is described by two permutations of the nn sheets (where the lifts of aa and bb lead), and it is connected when they act transitively — the second experiment below counts them.

Formal mathematicsF

Homotopy in Lean and Mathlib

Mathlib's notions match the lesson's, with one difference of convention: a homotopy F(t,s)F(t, s) 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 π1\pi_1 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 (1−t)v+tv=v(1 - t)v + tv = v that keeps endpoints fixed:

smul_combo_selfLean 4Proved here from basic factsFormally verified
/-- 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]
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/FundamentalGroup.leanTry it in the Lean web editor
straightLineHomotopyLean 4Formally verified
/-- **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 _ _
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/FundamentalGroup.leanTry it in the Lean web editor
paths_homotopic_in_vector_spaceLean 4Proved here from basic factsFormally verified
/-- 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⟩
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/FundamentalGroup.leanTry it in the Lean web editor
loop_nullhomotopicLean 4Proved here from basic factsFormally verified
/-- 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)
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/FundamentalGroup.leanTry it in the Lean web editor
vector_space_simply_connectedLean 4Applies a library theoremFormally verified
/-- 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 :=
  inferInstance
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/FundamentalGroup.leanTry it in the Lean web editor

Functoriality (Proposition 4a) and change of basepoint (Proposition 3):

map_compLean 4Proved here from basic factsFormally verified
/-- **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
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/FundamentalGroup.leanTry it in the Lean web editor
change_of_basepointLean 4Applies a library theoremFormally verified
/-- **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⟩
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/FundamentalGroup.leanTry it in the Lean web editor

The circle is AddCircle 1, that is R/Z\R/\Z; the covering pp is the quotient map. Mathlib proves the covering property, path lifting (Theorem 5a), and Theorem 6 itself, where the isomorphism is the winding number:

fact_one_posLean 4Formally verified
/-- 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⟩
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/FundamentalGroup.leanTry it in the Lean web editor
covering_real_circleLean 4Applies a library theoremFormally verified
/-- **`ℝ → ℝ/ℤ` 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
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/FundamentalGroup.leanTry it in the Lean web editor
path_liftingLean 4Applies a library theoremFormally verified
/-- **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
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/FundamentalGroup.leanTry it in the Lean web editor
pi1_circleLean 4Applies a library theoremFormally verified
/-- **`π₁(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⟩
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/FundamentalGroup.leanTry it in the Lean web editor
windingNumber_loopLean 4Applies a library theoremFormally verified
/-- 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 n
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/FundamentalGroup.leanTry it in the Lean web editor

Corollary 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).

circle_not_retractLean 4Proved here from basic factsFormally verified
/-- **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 w1
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/FundamentalGroup.leanTry it in the Lean web editor

Brouwer's theorem in dimension one, from the intermediate value theorem:

brouwer_intervalLean 4Proved here from basic factsFormally verified
/-- **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]⟩
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/FundamentalGroup.leanTry it in the Lean web editor

Finally, the free group on two generators — by van Kampen, π1\pi_1 of the figure eight — is not abelian. The proof maps it to the symmetric group S3S_3 and lets decide compare two permutations:

free_group_not_commLean 4Proved here from basic factsFormally verified
/-- **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'
  decide
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/FundamentalGroup.leanTry it in the Lean web editor

What 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 F2F_2. Cited from Mathlib: the covering R→R/Z\R \to \R/\Z, path lifting, π1(S1)≅Z\pi_1(S^1) \cong \Z 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 π1(S1∨S1)≅F2\pi_1(S^1 \vee S^1) \cong F_2, and Theorem 10.

ComputationC

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 (−π,π](-\pi, \pi]. 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 2π2\pi is the winding number; the program compares it with the contour integral 12πi∮dz/z\frac{1}{2\pi i}\oint dz/z, then watches a homotopy of circles and runs the argument of Corollary 8 on a cubic.

Winding numbers by lifting loops to the real linePythonNumerical approximationComputationally tested
"""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()
Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.

This is numerical evidence: the lift is correct only if consecutive samples turn by less than π\pi — the computational shadow of the Lebesgue number in the proof.

The second program works in π1(S1∨S1)=F2\pi_1(S^1 \vee S^1) = F_2. It reduces words, detects ab≠baab \ne ba with a homomorphism to S3S_3 (as the Lean proof does), and counts covering spaces of the figure eight by counting pairs of permutations.

The figure eight: free group words and covering spacesPythonExact computationExhaustive finite checkComputationally tested
"""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()
Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.

The counts are exact for n≤5n \le 5 sheets. The numbers 1,3,13,71,4611, 3, 13, 71, 461 of subgroups of index nn in F2F_2 grow faster than exponentially, while Z\Z 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

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 −1-1 and +1+1 around the two holes. Try to imagine the commutator loop aba−1b−1aba^{-1}b^{-1}: it winds 00 times around each hole, yet it cannot be shrunk, because π1\pi_1 of the twice-punctured plane is the non-abelian group F2F_2.

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.

p₁

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 Z2=π1(T2)\Z^2 = \pi_1(T^2). 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.

Torusa b a⁻¹ b⁻¹
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

Exercises

1. Homotopy and the fundamental group

Warm-upHuman

Which of these spaces are simply connected? (Choose all that apply.)

Choose all that apply

2. Homotopy and the fundamental group

Warm-upHuman

Under the isomorphism π1(S1,1)≅Z\pi_1(S^1, 1) \cong \mathbb{Z} of Theorem 6, what integer corresponds to the class of the loop γ(s)=e−6πis\gamma(s) = e^{-6\pi i s}?

3. Homotopy and the fundamental group

CoreHuman

In the proof that the degree is well defined, we lift a path homotopy FF from γ\gamma to γ′\gamma' to F~\tilde F, and then claim that t↦F~(1,t)t \mapsto \tilde F(1, t) is constant. Why is it constant?

Choose one

4. Homotopy and the fundamental group

CoreHuman

Brouwer's theorem says every continuous map D2→D2D^2 \to D^2 has a fixed point. For which of these spaces is there a continuous map to itself with no fixed point? (Choose all that apply.)

Choose all that apply

5. Homotopy and the fundamental group

CoreHuman

The closed orientable surface of genus 2 is an octagon with sides glued by the word aba−1b−1cdc−1d−1a b a^{-1} b^{-1} c d c^{-1} d^{-1}. What does the Seifert–van Kampen theorem give for its fundamental group?

Choose one

6. Homotopy and the fundamental group

CoreFormal

The 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?

Choose one

7. Homotopy and the fundamental group

CoreComputational

Implement path lifting for the angle. Write winding_number(points) for a list of non-zero complex numbers points describing a closed loop around 00 (the last point equals the first). Add up the changes of angle between consecutive points, each taken in (−π,π](-\pi, \pi], and return the total divided by 2π2\pi, rounded to the nearest integer.

Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.

8. Homotopy and the fundamental group

StretchHuman

How many connected 2-sheeted covering spaces does the figure eight S1∨S1S^1 \vee S^1 have, up to isomorphism?

9. Homotopy and the fundamental group

StretchHuman

In the plane with two holes, let aa and bb be loops going once around the first and the second hole. True or false: the loop aba−1b−1a b a^{-1} b^{-1}, which winds 00 times around each hole, is null-homotopic.

Choose one
Common misconceptionsH

Common misconceptions

Misconception

"Fundamental groups are always abelian." π1(S1)≅Z\pi_1(S^1) \cong \Z and π1(T2)≅Z2\pi_1(T^2) \cong \Z^2 are abelian, but π1(S1∨S1)\pi_1(S^1 \vee S^1) is the free group F2F_2, in which ab≠baab \ne ba; the surface groups of genus g≥2g \ge 2 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." S2S^2, S3S^3 and a point all have trivial π1\pi_1; S1S^1, the annulus and the solid torus all have π1≅Z\pi_1 \cong \Z. 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, π1=1\pi_1 = 1 does force S3S^3 — 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 aba−1b−1aba^{-1}b^{-1} of the loops aa, bb around them winds zero times around each hole but is not null-homotopic, since aba−1b−1≠1aba^{-1}b^{-1} \ne 1 in F2F_2. Winding numbers only see the abelianisation Z2\Z^2 of F2F_2.

Misconception

"Homotopic loops are the same as freely homotopic loops." In π1(X,x0)\pi_1(X, x_0) the basepoint must stay fixed during the homotopy. If the basepoint may move, loops are classified by the conjugacy classes of π1\pi_1 instead. For abelian groups like Z\Z there is no difference; in F2F_2, the loops abab and baba 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 XX at every moment. A loop around the origin of R2∖{0}\R^2 \setminus \{0\} cannot be dragged across the origin, even briefly — that is exactly what the first experiment shows when the circle's centre crosses 00.

ViewpointsH

Many ways of seeing

Topology— The first of the homotopy groups

π1\pi_1 is the first of the homotopy groups πn(X,x0)\pi_n(X, x_0), built from maps of spheres Sn→XS^n \to X; for n≥2n \ge 2 they are abelian. They are hard to compute: π3(S2)≅Z\pi_3(S^2) \cong \Z (Hopf, 1931), and the homotopy groups of spheres are still not fully known. Homology is easier and coarser. The Hurewicz theorem says that H1(X)H_1(X) is the abelianisation of π1(X)\pi_1(X) for path-connected XX, which is why winding numbers, which are homological, cannot see the commutator loop. The Poincaré conjecture, now Perelman's theorem, shows how much π1\pi_1 can know: a closed 3-manifold with trivial π1\pi_1 is homeomorphic to S3S^3. 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 ⟨S∣R⟩\langle S \mid R \rangle, 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 π1=⟨S∣R⟩\pi_1 = \langle S \mid R \rangle. 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 kk it is the absolute Galois group of kk, and for a complex algebraic variety it is the profinite completion of the topological π1\pi_1.

Analysis— Winding numbers as integrals

For a loop γ\gamma in C∖{a}\C \setminus \{a\} the degree is an integral: deg⁡=12πi∮γdzz−a\deg = \frac{1}{2\pi i} \oint_\gamma \frac{dz}{z - a}. 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 ω\omega on XX defines a homomorphism π1(X)→R\pi_1(X) \to \R, [γ]↦∫γω[\gamma] \mapsto \int_\gamma \omega, well defined by Stokes' theorem. The form dθ=(x dy−y dx)/(x2+y2)d\theta = (x\,dy - y\,dx)/(x^2 + y^2) on the punctured plane gives 2π2\pi 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 g≥2g \ge 2 carries a metric of constant curvature −1-1, and its universal cover is the hyperbolic plane, tiled by 4g4g-gons on which π1\pi_1 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 Z2\Z^2 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 SO(3)SO(3) has π1≅Z/2\pi_1 \cong \Z/2, with the double cover SU(2)→SO(3)SU(2) \to SO(3). This is the mathematics behind spin-½ particles, whose state changes sign under a 2π2\pi rotation, and behind the "belt trick": a 4π4\pi twist of a belt with fixed ends can be undone, a 2π2\pi twist cannot. In two spatial dimensions, the configuration space of nn identical particles has the braid group as π1\pi_1, 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 Π1(X)\Pi_1(X), a category in which every arrow is invertible. π1(X,x0)\pi_1(X, x_0) 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 ff induces a functor Π1(f)\Pi_1(f), 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 π1(S1)\pi_1(S^1) itself). In homotopy type theory the circle is a higher inductive type, and π1(S1)≅Z\pi_1(S^1) \cong \Z 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 11? 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 π1\pi_1.

History & global context

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 nn-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

Further reading

  • Allen Hatcher, Algebraic Topology (2002), chapter 1 — the standard modern account of π1\pi_1, 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.