Skip to main content

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 (called out by the audit for the OMEGA use-case): 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 OMEGA Swarm Phase 7 (Topological Signal Intelligence) — agent-signal denoising via L0 spectral filtering on a PMFG correlation 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.

Release files for hodgex 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hodgex 0.1.0
File Size Uploaded
hodgex-0.1.0.tar.gz 15.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for hodgex 0.1.0
File Interpreter ABI Platform
hodgex-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 27.5 kB

Release files / hodgex-0.1.0.tar.gz

Download URL hodgex-0.1.0.tar.gz
Size 15.7 kB
Tags Source
SHA-256 checksum
How to use checksums
3147cdd3c71a7228a709e022cc1739ef093e30676f013f38bcacf929437a3b62
BLAKE2b-256 checksum
How to use checksums
990d8554a2d54fb7c216925508e73a9d533086a759c165ee0e3c99d9926a3f36
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.3

Release files / hodgex-0.1.0-py3-none-any.whl

Download URL hodgex-0.1.0-py3-none-any.whl
Size 11.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d94601b95af68b7ad6dc809183e79c03da40fa3e005ad3a01853eae84944aa66
BLAKE2b-256 checksum
How to use checksums
91c86269bc7e158eef2a92dc7668d77f5f3398940c5fbd47901ed591e88903f4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.3

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page