Metadata-Version: 2.4
Name: hodgex
Version: 0.1.0
Summary: Hodge Laplacian + simplicial complex + 3-way Hodge decomposition on graphs. Pure scipy.sparse, 2-simplex (triangle) scope.
Author: Pierre Samson
Author-email: "Claude Opus (Anthropic)" <noreply@anthropic.com>
License: MIT
Project-URL: Homepage, https://github.com/darw007d/hodgex
Project-URL: Issues, https://github.com/darw007d/hodgex/issues
Keywords: hodge-laplacian,simplicial-complex,topology,spectral-graph-theory,hodge-decomposition,topological-signal-processing,tda
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Mathematics
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.23
Requires-Dist: scipy>=1.10
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Dynamic: license-file

# 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 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

```bash
pip install hodgex
```

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

## Quickstart

```python
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](https://github.com/darw007d/hedge-fund-mcp) Phase 7 (Topological Signal Intelligence) — agent-signal denoising via L0 spectral filtering on a PMFG correlation backbone. Sister library to [phawkes](https://pypi.org/project/phawkes/) (Hawkes processes), [fisherrao](https://pypi.org/project/fisherrao/) (information geometry), [tailcor](https://pypi.org/project/tailcor/) (tail-contagion decomposition), [diebold-yilmaz](https://pypi.org/project/diebold-yilmaz/) (spillover index). Same "small, tested, publishable" ethos.

## Authors

- **Pierre Samson** ([@darw007d](https://github.com/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](LICENSE).
