TDA Method

Zigzag Persistence

Drafting

What Is Zigzag Persistence?

Standard persistent homology watches a single expanding wave: features are born as the scale parameter grows and die when they merge. Zigzag persistence generalises this to a two-way tide: the wave can both advance and retreat, and features are tracked through both the incoming and outgoing water. This makes zigzag persistence appropriate for data that changes through time — populations that grow, shrink, merge, and split across sequential samples.

The name comes from the zigzag shape of the diagram connecting the sequence of spaces: arrows pointing left and right alternate, like the lines of a zigzag seam.

Mathematical Formulation

A zigzag persistence module is a sequence of vector spaces connected by linear maps in alternating directions:

V0V1V2VnV_0 \leftrightarrow V_1 \leftrightarrow V_2 \leftrightarrow \cdots \leftrightarrow V_n

where each \leftrightarrow denotes a map in either direction (forward or backward). This arises in practice from a sequence of spaces X0,X1,,XnX_0, X_1, \ldots, X_n connected by inclusion into unions:

X0X0X1X1X1X2X_0 \hookrightarrow X_0 \cup X_1 \hookleftarrow X_1 \hookrightarrow X_1 \cup X_2 \hookleftarrow \cdots

The Structure Theorem for zigzag modules (Carlsson–de Silva 2010) guarantees decomposition into interval modules I[b,d]\mathbb{I}[b,d], yielding a barcode exactly as in ordinary persistence. Feature intervals now represent periods during which a topological feature (component, loop, void) is present in the sequence.

MkI[bk,dk]M \cong \bigoplus_k \mathbb{I}[b_k, d_k]

Python Code Stub

import gudhi

def compute_zigzag_persistence(
    rips_complex_sequence: list,
) -> list[tuple[int, tuple[float, float]]]:
    """
    Compute zigzag persistence from a time-ordered list of precomputed Rips complexes.
    Each element is a Gudhi SimplexTree for a time window.
    Returns a list of (dimension, (birth, death)) pairs.

    The zigzag sequence encodes the alternating inclusions:
      X_0 -> X_0 u X_1 <- X_1 -> X_1 u X_2 <- X_2 -> ...

    This is built as an arrow filtration — a sequence of (simplex, is_addition)
    pairs — where is_addition=True adds a simplex (forward arrow) and
    is_addition=False removes one (backward arrow).

    Gudhi 3.9 API: compute_zigzag_persistence(arrow_filtration) returns a list
    of [dimension, birth, death] triples directly (not a ZigzagPersistence object).
    """
    # Step 1: seed with all simplices from the first complex (all forward arrows)
    prev_simplices: set[tuple[int, ...]] = set()
    first_simplices = {tuple(s) for s, _ in rips_complex_sequence[0].get_filtration()}
    arrow_filtration: list[tuple[list[int], bool]] = [
        (list(s), True) for s in first_simplices
    ]
    prev_simplices = first_simplices

    # Step 2: for each consecutive pair, forward-add new simplices then
    # backward-remove departed simplices to traverse X_i -> X_i u X_{i+1} <- X_{i+1}
    for st in rips_complex_sequence[1:]:
        next_simplices = {tuple(s) for s, _ in st.get_filtration()}
        # Forward arrows: add simplices present in next but not prev (X_i -> X_i u X_{i+1})
        for s in next_simplices - prev_simplices:
            arrow_filtration.append((list(s), True))
        # Backward arrows: remove simplices present in prev but not next (X_i u X_{i+1} <- X_{i+1})
        for s in prev_simplices - next_simplices:
            arrow_filtration.append((list(s), False))
        prev_simplices = next_simplices

    # compute_zigzag_persistence returns list of [dim, birth, death] triples
    raw = gudhi.zigzag_persistence.compute_zigzag_persistence(arrow_filtration)
    return [(dim, (birth, death)) for dim, birth, death in raw]

Application to the Research Programme

Zigzag persistence is the primary method in Paper 3, where it is applied to five-year rolling windows of the BHPS/Understanding Society linked panel to track how employment trajectory topology evolves across macroeconomic cycles. The topological complexity index — a summary statistic derived from the sum of H₁ barcode lengths per window — is shown to lead official unemployment statistics by approximately two quarters.

In Paper 7, zigzag-derived complexity indices serve as time-series features in the geometric forecasting model, contributing approximately 15% of combined SHAP feature importance.

The primary computational challenge is that zigzag persistence cannot be trivially parallelised across windows (the zigzag structure requires sequential computation), leading to the ~14-hour runtime on HPC hardware documented in the Computational Log.