4  Simplicial homology

“Her thoughts were theorems, her words a problem,
As if she deem’d that mystery would ennoble ’em.”
— Lord Byron, in Don Juan

Simplicial complexes give us finite descriptions of spaces. Homology turns those descriptions into algebra. Our goal is to understand what the computation measures, rather than merely press the “count holes” button and hope for the best.

We will first use integer coefficients to explain orientations, then use the field \(\mathbb F_2\) for the calculations in this book. Keep the coefficient system fixed whenever you compare answers.

4.1 What is a hole?

A circle contains a loop with no filling. A hollow sphere contains a closed surface with no solid filling. A solid ball has neither kind of hole.

The phrase “something that is not there” is good intuition and a terrible algorithm. Homology instead asks which closed chains can be expressed as boundaries of higher-dimensional chains.

Consider the complex \(S\) with vertices \(a,b,c\) and all three edges, but no filled triangle:

An ugly simplicial complex homeomorphic to a circle.

Its realization has one loop. Adding the \(2\)-simplex \(\{a,b,c\}\) will fill that loop. We want algebra to see the difference.

4.2 Chains, coefficients, and orientation

\(S\) with an orientation on its edges.

An oriented edge has a beginning and an end, so define

\[ \partial_1([x,y])=y-x. \]

What could \(y-x\) mean when \(x\) and \(y\) are vertices, rather than numbers? It is a formal sum. The symbols name building blocks, and coefficients say how much of each block occurs.

Definition 4.1 With integer coefficients, \(C_k(K;\mathbb Z)\) is the free abelian group generated by the oriented \(k\)-simplices of \(K\). A chain is a finite sum with integer coefficients. Reversing orientation changes the sign; for example, \([b,a]=-[a,b]\).

With coefficients in a field \(\mathbb F\), \(C_k(K;\mathbb F)\) is a vector space with one basis element per \(k\)-simplex, after choosing one orientation for each simplex, and coefficients in \(\mathbb F\).

A free abelian group is not a vector space: division by an arbitrary nonzero scalar is unavailable over \(\mathbb Z\). Its elements can be sums such as \(2a-b+3c\). Over \(\mathbb R\), the analogous chain space permits real coefficients. Over \(\mathbb F_2=\{0,1\}\), addition is modulo two:

\[ 1+1=0,\qquad -1=1. \]

Thus an \(\mathbb F_2\) chain is a selection of simplices. Adding two selections keeps the simplices that occur in exactly one of them. Orientation signs disappear, because a minus sign equals a plus sign. This is convenient for computation, and it is TDARipserer.jl’s default coefficient field.

For the unfilled triangle, \(C_0\) has three vertex generators, \(C_1\) has three edge generators, and \(C_2=0\). Remember that a chain is a formal combination of those generators, not an arbitrary curve drawn through the surrounding plane.

4.3 The boundary operator

Extend the boundary linearly from simplices to chains. For an oriented simplex,

\[ \partial_k([v_0,\ldots,v_k]) =\sum_{i=0}^k(-1)^i[v_0,\ldots,\widehat v_i,\ldots,v_k], \]

where the hat means “remove this vertex.” For example,

\[ \partial_2([a,b,c])=[b,c]-[a,c]+[a,b] =[a,b]+[b,c]+[c,a]. \]

A triangle’s boundary consists of its three edges with compatible orientations. Over \(\mathbb F_2\), it is simply the sum of those edges. We use ordinary, unreduced homology, for which \(\partial_0=0\).

A boundary has no boundary of its own:

\[ \partial_k\partial_{k+1}=0. \]

For the triangle, applying \(\partial_1\) to its boundary gives

\[ (b-a)+(c-b)+(a-c)=0. \]

Every vertex contribution cancels. In higher dimensions, each codimension-two face occurs twice with opposite signs—or twice modulo two. The chain spaces and these boundary maps together form a chain complex.

4.4 Cycles and boundaries

Definition 4.2 The cycles are the chains with zero boundary:

\[Z_k=\ker\partial_k.\]

The boundaries are chains obtained as the boundary of a chain one dimension higher:

\[B_k=\operatorname{im}\partial_{k+1}.\]

Because \(\partial_k\partial_{k+1}=0\), we always have \(B_k\subseteq Z_k\).

For our unfilled triangle,

\[z=[a,b]+[b,c]+[c,a]\]

is a cycle. It is not a boundary in \(S\), because \(S\) has no \(2\)-simplices and hence no nonzero \(2\)-chains. If we add the filled triangle, the very same chain becomes \(\partial_2([a,b,c])\). Being a boundary depends on the whole complex, rather than just the appearance of the cycle.

Boundaries can be sums of the boundaries of several simplices. A square can be filled by two triangles even though no single triangle has the square as its boundary. We will calculate that shortly.

4.5 Homology: the punchline

We want to forget cycles that can be filled. We also want two cycles to count as the same feature if one can be changed into the other by adding a boundary.

Definition 4.3 The \(k\)-th homology is

\[H_k(K;\mathbb F)=Z_k/B_k.\]

This quotient identifies cycles \(z\) and \(z'\) exactly when \(z-z'\in B_k\). A class \([z]\) is zero precisely when \(z\) is a boundary. With field coefficients, \(H_k\) is a vector space and its Betti number is

\[\beta_k(K;\mathbb F)=\dim_{\mathbb F}H_k(K;\mathbb F).\]

The bracket \([z]\) here means a homology class, rather than an oriented simplex. A class is a collection of equivalent cycles, not a preferred curve or a particular basis chosen by the computer.

With integer coefficients, the quotient is an abelian group and the Betti number is the rank of its free part. Integer homology can also contain torsion, which these ranks do not record. Betti numbers over different fields need not agree; we use \(\mathbb F_2\) consistently in the examples below.

Betti number Interpretation for familiar shapes
\(\beta_0\) Connected components
\(\beta_1\) Independent loop classes
\(\beta_2\) Independent closed-surface classes, such as a hollow sphere

“Independent” matters. Walking around the same loop twice does not produce a second independent hole; over \(\mathbb F_2\), it produces the zero chain.

4.5.1 Two cycles, one class

Here is a small modification of our square, using \(\mathbb F_2\) coefficients. Take its four side edges, add the diagonal \([a,c]\), and fill only the triangle \([a,c,d]\). Call this complex \(L\). It is an illustrative complex, not one of the square’s Rips levels: the Rips rule would add all four triangles at the same diagonal scale.

The outside square cycle and the remaining triangle cycle are

\[ z=[a,b]+[b,c]+[c,d]+[d,a],\qquad z'=[a,b]+[b,c]+[a,c]. \]

Both have zero boundary, and

\[ z+z'=[c,d]+[d,a]+[a,c]=\partial_2([a,c,d]). \]

So \([z]=[z']\) in \(H_1(L;\mathbb F_2)\). The two drawings trace different routes, but their difference is a filled triangle. Neither class is zero: the unfilled triangle \([a,b,c]\) still supplies one loop. The quotient counts that feature once.

4.6 The square calculation, by hand

Return to the Rips complexes in Section 3.6. At \(1\leq\epsilon<\sqrt2\), use the edge order \([a,b],[b,c],[c,d],[d,a]\) and vertex order \(a,b,c,d\). Over \(\mathbb F_2\), the boundary matrix is

\[ D_1=\begin{array}{c|cccc} &ab&bc&cd&da\\\hline a&1&0&0&1\\ b&1&1&0&0\\ c&0&1&1&0\\ d&0&0&1&1 \end{array}. \]

Read a column as an edge’s two endpoints. Multiplying by the coefficient vector \((1,1,1,1)^\mathsf T\) gives zero: every vertex occurs twice. That vector describes the square loop.

The first three columns are independent; the fourth is their sum. Therefore \(\operatorname{rank}D_1=3\) and \(\dim\ker D_1=4-3=1\). There are no triangles, so \(B_1=0\) and

\[\beta_1=1,\qquad\beta_0=\dim C_0-\operatorname{rank}D_1=4-3=1.\]

Before \(\epsilon=1\), there are no edges: \(D_1=0\), \(\beta_0=4\), and \(\beta_1=0\).

4.6.1 When the diagonals enter

At \(\epsilon=\sqrt2\), the Rips complex has six edges, four triangles, and one tetrahedron. Extend the edge order above with \([a,c],[b,d]\). The triangle boundary matrix is

\[ D_2=\begin{array}{c|cccc} &abc&acd&abd&bcd\\\hline ab&1&0&1&0\\ bc&1&0&0&1\\ cd&0&1&0&1\\ da&0&1&1&0\\ ac&1&1&0&0\\ bd&0&0&1&1 \end{array}. \]

The square cycle now satisfies

\[ z=\partial_2([a,b,c]+[a,c,d]). \]

The shared diagonal occurs twice and cancels. This is a boundary of a chain of two triangles, exactly the filling we needed.

For the complete complex, \(\operatorname{rank}D_1=3\) and \(\operatorname{rank}D_2=3\). Rank–nullity gives the general formula

\[ \beta_k=\dim C_k-\operatorname{rank}D_k-\operatorname{rank}D_{k+1}. \]

Thus \(\beta_1=6-3-3=0\). The tetrahedron’s boundary is the sum of all four faces, so \(D_3=(1,1,1,1)^\mathsf T\) has rank \(1\). It kills the surface class: \(\beta_2=4-3-1=0\). If we omitted the tetrahedron, its surface would instead have \(\beta_2=1\).

4.6.2 Check the arithmetic in Julia

Ordinary real-valued matrix rank is not the correct operation for arbitrary finite-field calculations. Here is a small row-reduction routine that performs every addition modulo two. You can follow the hand calculation without studying this implementation.

Check the square boundary matrices over F₂
function rank_mod2(A)
    M = mod.(copy(A), 2)
    row = 1
    for col in axes(M, 2)
        row > size(M, 1) && break
        pivot = findfirst(!iszero, @view M[row:end, col])
        isnothing(pivot) && continue
        pivot += row - 1
        M[row, :], M[pivot, :] = copy(M[pivot, :]), copy(M[row, :])
        for i in (row + 1):size(M, 1)
            if M[i, col] == 1
                M[i, :] .= mod.(M[i, :] .+ M[row, :], 2)
            end
        end
        row += 1
    end
    return row - 1
end

D1_square = [1 0 0 1; 1 1 0 0; 0 1 1 0; 0 0 1 1]
D1_full = hcat(D1_square, [1, 0, 1, 0], [0, 1, 0, 1])
D2_full = [1 0 1 0; 1 0 0 1; 0 1 0 1;
           0 1 1 0; 1 1 0 0; 0 0 1 1]
D3_full = ones(Int, 4, 1)

@assert all(iszero, mod.(D1_full * D2_full, 2))
@assert all(iszero, mod.(D2_full * D3_full, 2))
@assert rank_mod2(D1_square) == 3
@assert rank_mod2(D2_full) == 3

(beta0 = 4 - rank_mod2(D1_full),
 beta1 = 6 - rank_mod2(D1_full) - rank_mod2(D2_full),
 beta2 = 4 - rank_mod2(D2_full) - rank_mod2(D3_full))
(beta0 = 1, beta1 = 0, beta2 = 0)

The answer is (beta0 = 1, beta1 = 0, beta2 = 0). All three square stages can now be summarized:

Scale \(\beta_0\) \(\beta_1\) \(\beta_2\)
\(0\leq\epsilon<1\) 4 0 0
\(1\leq\epsilon<\sqrt2\) 1 1 0
\(\epsilon\geq\sqrt2\) 1 0 0

4.7 Why homology matters for data

Homeomorphic realizations have the same homology. Different Betti numbers therefore rule out a homeomorphism, but matching numbers do not prove one. Homology is also preserved by the weaker relation of homotopy equivalence (Hatcher 2002).

More concretely, we can store a complex as lists of simplices, write its boundary matrices, and calculate kernels and images. These finite algebraic operations tell us about spaces containing infinitely many points. That is quite a good deal.

Our table records homology at each scale, but it has not told us which class survives from one scale to another. Persistent homology adds the maps between these vector spaces. We will trace the square’s loop through those maps in Section 7.2.

4.8 Stop and predict

  1. Is the square loop a boundary at \(\epsilon=1.1\)? What about \(\epsilon=1.5\)?

At \(1.1<\sqrt2\), there are no triangles, so the loop is not a boundary and represents a nonzero class. At \(1.5>\sqrt2\), it is the boundary of \([a,b,c]+[a,c,d]\) and represents zero. The edge chain still exists; its homology class has changed.

  1. Over \(\mathbb F_2\), what is the sum of the boundaries of two triangles sharing an edge?

The shared edge occurs twice and vanishes modulo two. For \([a,b,c]\) and \([a,c,d]\), the result is the four outside square edges. A boundary need not be the boundary of a single simplex.

  1. Two different cycles differ by the boundary of a filled triangle. Do they give two independent homology classes?

No. Their difference lies in \(B_1\), so they represent the same element of \(Z_1/B_1\). Different cycle drawings or different representatives returned by software can describe the same feature.