Skip to content

BrainSurfing-tech/hodgex

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

hodgex

Hodge Laplacians, simplicial complexes (up to 2-simplices), and the 3-way gradient + curl + harmonic Hodge decomposition of edge flows. Pure scipy.sparse, no C++ dependencies, no optional backends.

Why it exists

The topological-signal-processing ecosystem on PyPI has gaps the audit for our Phase 7 work called out explicitly:

  • toposigdoes not exist (hallucinated by LLM ideation)
  • HodgeLaplacian (PyPI) — fake package, do not install
  • toponetx — real but v0.x with volatile API surface; not reliable for production
  • graph-hodge — real, but graph-only, no simplicial complex support

hodgex fills the narrow, stable slice: build a 2-complex, compute its boundary matrices and Hodge Laplacians, project signals onto the low-frequency spectral basis, and get the canonical 3-way edge-flow decomposition. Everything is testable against hand-checkable fixtures (K5, C6, K4-with-filled-triangles).

Install

pip install hodgex

Python ≥ 3.9, numpy ≥ 1.23, scipy ≥ 1.10.

Quickstart

import numpy as np
from hodgex import SimplicialComplex2, hodge_laplacian_0, hodge_laplacian_1, low_freq_projection, hodge_decompose_edge

# Build K5 (complete graph on 5 vertices) and fill every triangle
sc = SimplicialComplex2.from_edges(
    n_vertices=5,
    edges=[(i, j) for i in range(5) for j in range(i + 1, 5)],
).fill_all_triangles()

# Boundary matrices: B1 is (V, E), B2 is (E, T)
B1, B2 = sc.boundary_matrices()

# Hodge Laplacians
L0 = hodge_laplacian_0(B1)           # vertex Laplacian = classical graph Laplacian
L1 = hodge_laplacian_1(B1, B2)       # edge Laplacian (the "real" Hodge object)

# Spectral smoothing: project a vertex signal onto the k lowest eigenvectors of L0
signal = np.array([1., 2., 3., 4., 100.])  # vertex 4 is an outlier
smoothed = low_freq_projection(signal, L0, k=2)

# 3-way Hodge decomposition of an edge flow
edge_flow = np.random.default_rng(0).standard_normal(B1.shape[1])
grad, curl, harm = hodge_decompose_edge(edge_flow, B1, B2)
assert np.allclose(grad + curl + harm, edge_flow)

What's inside

Function Returns
SimplicialComplex2(n, edges, triangles) an oriented 2-complex; rejects self-loops, enforces triangle ⊂ edges
.fill_all_triangles() mutates to add every 3-clique as a triangle (fills C_n's cycles)
.boundary_matrices() returns (B1, B2) as scipy.sparse.csr_matrix
hodge_laplacian_0(B1) L0 = B1 @ B1.T — classical graph Laplacian
hodge_laplacian_1(B1, B2) L1 = B1.T @ B1 + B2 @ B2.T — edge Laplacian
hodge_laplacian_2(B2) L2 = B2.T @ B2
low_freq_projection(signal, L, k) topology-aware smoothing: project onto k smallest eigenvectors
kernel_dimension(L) Betti number (β_0 from L0, β_1 from L1) via low-eigenvalue counting
hodge_decompose_edge(flow, B1, B2) (grad, curl, harm) — sums exactly to flow, mutually L2-orthogonal

The math (1-minute version)

An oriented 2-complex has a chain complex C_2 → C_1 → C_0 with boundary maps ∂_2 = B2 (triangles → edges) and ∂_1 = B1 (edges → vertices). By construction ∂_1 ∘ ∂_2 = 0 — hodgex asserts this at build time.

The Hodge Laplacian at dimension k combines the two adjacent boundaries:

L0 = ∂_1 ∂_1ᵀ                        (vertices: the combinatorial graph Laplacian)
L1 = ∂_1ᵀ ∂_1 + ∂_2 ∂_2ᵀ              (edges: down-Laplacian + up-Laplacian)
L2 = ∂_2ᵀ ∂_2                        (triangles)

The Hodge decomposition theorem on C_1 (edge signals):

C_1 = im(∂_1ᵀ) ⊕ im(∂_2) ⊕ ker(L1)
     ≡ gradient  ⊕  curl    ⊕  harmonic

Every edge flow splits uniquely into:

  • a gradient part: ∂_1ᵀ v for some vertex potential v (conservative flow)
  • a curl part: ∂_2 t for some triangle circulation t (vortex flow)
  • a harmonic part: in the kernel of L1 — neither a gradient nor a curl (persistent cycles)

The three subspaces are mutually L²-orthogonal. The dimension of the harmonic subspace equals β_1, the first Betti number — the number of independent 1-cycles not filled in by triangles.

Key subtlety: on a connected graph, the kernel of L0 is only the constant vector (β_0 = 1). So the "harmonic component of a vertex signal" is trivially the signal's mean. The interesting content of vertex-signal smoothing is the low-eigenvalue projection onto L0 — low_freq_projection(signal, L0, k) returns exactly this. The genuine 3-way gradient + curl + harmonic split only appears on edge signals (1-forms); hence hodge_decompose_edge.

Correctness

16 unit tests cover:

Test Checks
K5 spectrum L0 eigenvalues exactly [0, 5, 5, 5, 5]
K5 triangle count fill_all_triangles produces 10 triangles (C(5,3))
C6 β_1 one independent cycle on a 6-gon
C3 unfilled β_1 = 1
C3 filled β_1 = 0 (triangle kills the cycle)
K4 filled β_1 = 0
Two disjoint edges β_0 = 2 (matches connected components)
Chain complex B1 @ B2 = 0 exactly at machine precision
Low-freq k=1 returns the mean broadcast
Low-freq k monotone more eigenvectors → smaller reconstruction error
Hodge decomp sum grad + curl + harm == flow
Harmonic on C6 pure-cycle flow projects onto the 1-dim L1 kernel
Kernel dimension helper matches dense eigvalsh count
Input validation self-loops, missing triangle edges, out-of-range vertices all raise

Run with pytest.

Roadmap

v0.2 (planned):

  • Weighted Hodge Laplacian (per-edge weights for non-combinatorial cases)
  • 3-simplex (tetrahedron) support, capped — compute grows as O(C(n, 4))
  • Persistent homology wrapper (bridge to ripser for the Phase 7B path)
  • GPU-backed eigendecomposition via cupy.sparse optional extra

Who's using it

Built for a signal-denoising application (L0 spectral filtering on a correlation-network backbone). Sister library to phawkes (Hawkes processes), fisherrao (information geometry), tailcor (tail-contagion decomposition), diebold-yilmaz (spillover index). Same "small, tested, publishable" ethos.

Authors

  • Pierre Samson (@darw007d) — idea, use-case, design decisions
  • Claude Opus (Anthropic) — implementation and tests

Citations

  • Lim, L.-H. (2020). Hodge Laplacians on graphs. SIAM Review 62(3), 685-715.
  • Schaub, M.T. et al. (2020). Signal processing on higher-order networks: Livin' on the edge... and beyond. Signal Processing 187.
  • Eckmann, B. (1944). Harmonische Funktionen und Randwertaufgaben in einem Komplex. Commentarii Mathematici Helvetici 17.

License

MIT — see LICENSE.

About

Hodge Laplacians + 3-way Hodge decomposition on simplicial 2-complexes. Pure scipy.sparse. Fills PyPI gaps in topological signal processing.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages