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:
toposig— does not exist (hallucinated by LLM ideation)HodgeLaplacian(PyPI) — fake package, do not installtoponetx— real but v0.x with volatile API surface; not reliable for productiongraph-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ᵀ vfor some vertex potentialv(conservative flow) - a curl part:
∂_2 tfor some triangle circulationt(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.sparseoptional 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.
Metadata
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)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| hodgex-0.1.0.tar.gz | 15.7 kB | Without provenance | Details for hodgex-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| hodgex-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for hodgex-0.1.0-py3-none-any.whl |
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
|
Security for hodgex 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.