Poincaré’s fundamental group (1895)#

Loops from a base point, up to deformation, form a group, \(\pi_1\). For a complex it can be read off combinatorially: contract a spanning tree of the edges, keep one generator per remaining edge, and impose one relation per triangle. Tietze moves then shrink the presentation. The torus gives \(\langle a, b \mid aba^{-1}b^{-1}\rangle\) (up to naming), the projective plane \(\langle a \mid a^2\rangle\), and abelianizing gives back \(H_1\).

import matplotlib.pyplot as plt

from mathematicskit.topology import (
    SimplicialComplex,
    abelianization,
    circle,
    fundamental_group,
    homology,
    klein_bottle,
    mobius_strip,
    projective_plane,
    sphere,
    torus,
)

wedge = SimplicialComplex([[0, 1], [1, 2], [2, 0], [0, 3], [3, 4], [4, 0]])
spaces = {
    "circle": circle(5),
    "figure eight": wedge,
    "sphere": sphere(2),
    "torus": torus(3, 3),
    "Möbius strip": mobius_strip(5),
    "projective plane": projective_plane(),
    "Klein bottle": klein_bottle(3, 3),
}
for name, K in spaces.items():
    raw = fundamental_group(K, simplify=False)
    P = fundamental_group(K)
    print(f"{name:>16}: {len(raw.generators):2d} edge generators, {len(raw.relations):2d} relations -> {P}")
    print(f"{'':>16}  abelianized: {abelianization(P)}, H_1 = {homology(K).group(1)}")
          circle:  1 edge generators,  0 relations -> < a >
                  abelianized: Z, H_1 = Z
    figure eight:  2 edge generators,  0 relations -> < a, b >
                  abelianized: Z^2, H_1 = Z^2
          sphere:  3 edge generators,  4 relations -> 1
                  abelianized: 0, H_1 = 0
           torus: 19 edge generators, 18 relations -> < a, b | BabA >
                  abelianized: Z^2, H_1 = Z^2
    Möbius strip: 11 edge generators, 10 relations -> < a >
                  abelianized: Z, H_1 = Z
projective plane: 10 edge generators, 10 relations -> < a | aa >
                  abelianized: Z/2, H_1 = Z/2
    Klein bottle: 19 edge generators, 18 relations -> < a, b | babA >
                  abelianized: Z + Z/2, H_1 = Z + Z/2

The spanning tree on the 3 x 3 torus#

Drawn on the square with opposite sides glued: the 8 tree edges are contracted, and the other 19 edges are generators. The 18 triangles then cut them down to two, \(a\) and \(b\), with one relation.

T = torus(3, 3)
pos = {i * 3 + j: (i, j) for i in range(3) for j in range(3)}
P_raw = fundamental_group(T, simplify=False)
fig, ax = plt.subplots(figsize=(5.5, 5.5))
for i in range(3):
    for j in range(3):
        for di, dj in ((1, 0), (0, 1), (1, 1)):
            a, b = i * 3 + j, ((i + di) % 3) * 3 + (j + dj) % 3
            edge = (min(a, b), max(a, b))
            is_generator = edge in P_raw.generators
            ax.plot([i, i + di], [j, j + dj], color="0.7" if is_generator else "tab:green", lw=1 if is_generator else 3)
for v, (i, j) in pos.items():
    ax.annotate(str(v), (i, j), ha="center", va="center", bbox={"boxstyle": "circle", "fc": "w"})
ax.add_patch(plt.Rectangle((0, 0), 3, 3, fill=False, ls="--"))
ax.set_aspect("equal")
ax.axis("off")
ax.set_title(f"spanning tree (green) of the torus; π₁ = {fundamental_group(T)}")
spanning tree (green) of the torus; π₁ = < a, b | BabA >
Text(0.5, 1.0, 'spanning tree (green) of the torus; π₁ = < a, b | BabA >')

Total running time of the script: (0 minutes 0.027 seconds)

Gallery generated by Sphinx-Gallery