# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
See also: [ARCHITECTURE.md](ARCHITECTURE.md) for detailed module design, [FEATURES.md](FEATURES.md) for feature status, [DEVELOPMENT.md](DEVELOPMENT.md) for task tracking.

## Project Overview

`hyperct` (v0.3.5) is a Python library for generating low-memory simplicial complex structures via hypercube triangulations and sub-triangulations. It triangulates high-dimensional domains (up to 10D+) with support for symmetry constraints (reducing complexity by O(n!)), scalar/vector field associations, inequality constraints for non-convex domains, multiple refinement strategies, pluggable computation backends (numpy/multiprocessing/GPU), discrete differential geometry (DDG) dual mesh computation with curvature, and disconnectivity graph visualization.

## Commands

```bash
# Install in development mode
pip install -e .
pip install -e ".[dev]"       # with test dependencies
pip install -e ".[plotting]"  # with matplotlib
pip install -e ".[gpu]"       # with PyTorch
pip install -e ".[docs]"      # with Sphinx

# Run all tests (skipping benchmarks)
pytest --benchmark-skip

# Run specific test suites
pytest hyperct/tests/test__hyperct.py::TestCube
pytest hyperct/tests/test__hyperct.py::TestSymmetry
pytest hyperct/tests/test_plotting.py
pytest hyperct/tests/test_parallel.py
pytest hyperct/tests/test_star_refinement.py
pytest hyperct/tests/test_examples.py
pytest hyperct/tests/test_gpu.py
pytest hyperct/tests/test_ddg.py
pytest hyperct/tests/test_vis_disc.py

# Run specific test
pytest hyperct/tests/test__hyperct.py::TestCube::test_1_1_2D_cube_init

# Run with coverage
pytest --cov=hyperct --benchmark-skip

# Run benchmarks
pytest hyperct/tests/test_benchmarks.py --benchmark-only

# Save benchmark results for a named version
pytest hyperct/tests/test_benchmarks.py --benchmark-save=v0.3.5

# Compare against saved baseline
pytest hyperct/tests/test_benchmarks.py --benchmark-compare=0001_v0.3.5
```

**Dependencies**: Only `numpy>=1.16.0` is required.
- Optional: `matplotlib>=3.0`, `polyscope` (plotting), `torch>=2.0` (GPU)
- Dev: `pytest>=6.0`, `pytest-cov>=2.10`, `pytest-benchmark>=3.4`
- Docs: `sphinx>=7.0`, `sphinx-rtd-theme>=2.0`, `myst-parser>=2.0`, `sphinx-autodoc-typehints>=1.25`

## Architecture Summary

See [ARCHITECTURE.md](ARCHITECTURE.md) for full details.

### Data Flow

```
Complex(dim) → .triangulate() → .split_generation() or .refine(n) → Complex.V / Complex.H
                                                                      ↓
                                                          ddg.compute_vd(HC) → HC.Vd (dual mesh)
```

### Module Map

| Module | Lines | Purpose |
|--------|-------|---------|
| `_complex.py` | ~2888 | Main `Complex` class orchestrator |
| `_vertex.py` | ~836 | Vertex hierarchy + cache containers |
| `_backend.py` | ~469 | Backend protocol (numpy/multiprocessing/torch) |
| `_plotting.py` | ~892 | Matplotlib visualization (1D/2D/3D) |
| `_vertex_group.py` | ~90 | Cell/Simplex/Subgroup containers |
| `_field.py` | ~56 | Field cache (mostly superseded by VertexCacheField) |
| `_simplex.py` | ~78 | SimplexBase/SimplexOrdered |
| `_misc.py` | ~127 | Arrow3D, custom LRU cache |
| `_vis_disc.py` | ~1178 | Disconnectivity graph visualization (Pele-derived, GPLv3, no external deps) |
| `plots.py` | ~267 | Demo plotting code with test functions |
| `ddg/` | ~1961 | DDG dual mesh computation + curvature |

### Key Classes

- **`Complex`**: Main entry point. Holds `V` (VertexCache), `H` (generation dict), `Vd` (dual cache after DDG)
- **`VertexBase`** → `VertexCube` / `VertexScalarField` / `VertexVectorField`: Vertex types
- **`VertexCacheBase`** → `VertexCacheIndex` / `VertexCacheField`: O(1) lookup caches with deferred pool processing
- **`BatchBackend`** (Protocol) → `NumpyBackend` / `MultiprocessingBackend` / `TorchBackend`

### Key Architectural Patterns

- **Cyclic Product Structure**: Hypercubes as C2 x C2 x ... x C2. Vertex connections via coset-based parallel connections
- **Generation-Based Refinement**: `H[gen]` stores Cell/Simplex objects per generation
- **Lazy Evaluation**: `refine(n)` uses generators + exception handling for target vertex count
- **Symmetry Reduction**: `symmetry=[0, 0, 0]` maps variables to groups, reduces by O(n!)
- **Backend Abstraction**: Protocol-based dispatch for numpy/multiprocessing/GPU computation
- **Strategy Pattern** (DDG): `compute_vd(HC, method=...)` accepts `"barycentric"`, `"circumcentric"`, or callable
- **Pool-Based Deferred Computation**: `fpool`/`gpool` sets batch field evaluation and constraint checks

## Test Structure

Nine test files (~3360 lines total, excluding legacy):

| File | Tests | Purpose |
|------|-------|---------|
| `test__hyperct.py` | ~40 | Core triangulation (TestCube, TestSymmetry) |
| `test_plotting.py` | 18 | Visualization functions |
| `test_star_refinement.py` | 21 | Star refinement operations |
| `test_parallel.py` | 15 | Parallel processing |
| `test_examples.py` | ~20 | Coverage for example code paths (refine, minimiser, constraints) |
| `test_gpu.py` | ~36 | GPU/backend tests |
| `test_ddg.py` | ~27 | DDG dual mesh, operators, curvature |
| `test_vis_disc.py` | ~43 | Disconnectivity graph visualization |
| `test_benchmarks.py` | ~25 | Performance benchmarks (pytest-benchmark) |

**Test naming**: `test_{group}_{sub}_{dim}D_cube|symm_init|splits`

**Reference data**: JSON files in `hyperct/tests/test_data/`, format: `test_{n+1}_{gen+1}_{n}D_{cube|symm}_gen_{gen}[_s_{symmetry}].json`

**Known issues**: 4D+ symmetry tests are `xfail`. High-dimensional cube tests (6D+) are `skip` (slow).

**Legacy**: `test__hyperct_old.py` (~1775 lines) is archived and not run in the normal test suite.

## Constraint System

- Inequality: `g(x) <= 0` (internally: `g(x) < 0` means infeasible, vertex gets `f=inf`)
- Constraints as dicts: `{'type': 'ineq', 'fun': callable, 'args': tuple}`
- Single dict or list of dicts accepted
- Non-convex domains created by cutting infeasible regions from the convex hypercube

## Domain and Bounds

- Default: unit hypercube `[0, 1]^dim`
- Custom: `domain=[(lower, upper), ...]` list of tuples per dimension

## DDG Module (`hyperct.ddg`)

Discrete Differential Geometry dual mesh computation with curvature operators.

**Public API**:
- `compute_vd(HC, method="barycentric"|"circumcentric"|callable, cdist=1e-10)` — Compute dual mesh
- `e_star(v_i, v_j, HC)` — Hodge star of primal edge
- `v_star(v_i, v_j, HC)` — Dual flux planes/volumes
- `d_area(v)` — Dual area of primal vertex
- `barycenter(verts)` / `circumcenter(verts)` — Placement strategies
- `HNdC_ijk(v_i, v_j, v_k)` — Dual edge/area via Heron's formula
- `normal_area(v, HC)` — Normal area at vertex
- `mean_curvature(v, HC)` — Mean curvature at vertex
- `integrated_curvature(v, HC)` — Integrated curvature at vertex

**Supports**: 1D (midpoint), 2D (triangle), 3D (tetrahedron), N-D (generalized circumcenter via linear solve).

**Internal modules**:

| Module | Lines | Purpose |
|--------|-------|---------|
| `_compute_dual.py` | ~653 | Unified 1D/2D/3D/N-D dual computation |
| `_operators.py` | ~306 | DDG operators (e_star, v_star, d_area) |
| `_curvature.py` | ~283 | Curvature computations (HNdC_ijk, mean/integrated curvature) |
| `plot_dual.py` | ~202 | Matplotlib dual mesh visualization |
| `_plot_polyscope.py` | ~182 | Polyscope 3D visualization |
| `_geometry.py` | ~158 | Geometry helpers (normalized, merge, area/volume) |
| `_strategies.py` | ~128 | Dual placement strategies (barycenter, circumcenter) |

**Legacy**: `ddg/barycentric/` and `ddg/circumcentric/` submodules are deprecated, emit warnings on import.

## Disconnectivity Graphs (`_vis_disc.py`)

Energy landscape visualization adapted from Pele (GPLv3). Fully self-contained — no external dependencies (networkx was removed and replaced with internal implementations).

**Key classes**:
- `SimpleGraph`: Lightweight undirected graph (replaces networkx.Graph)
- `UnionFind`: Disjoint set structure (replaces networkx.utils.UnionFind)
- `Tree` / `DGTree`: Tree-based disconnectivity graph with parent/children navigation
- `TreeLeastCommonAncestor`: LCA computation for barrier tree construction
- `DisconnectivityGraph`: Main class for building and plotting barrier trees from a Complex

## Examples

16 example scripts in `examples/`:

| Example | Features |
|---------|----------|
| `basic_triangulation.py` | 2D/3D triangulation, mesh refinement |
| `refinement_levels.py` | Generation splitting, lazy `refine(n)` |
| `scalar_field.py` | Scalar field association (Eggholder function) |
| `constrained_domain.py` | Inequality constraints, non-convex domains |
| `symmetry.py` | Symmetry reduction |
| `jitter_1d.py` | 1D animation with sinusoidal wobble |
| `jitter_2d.py` | 2D animation with travelling-wave distortion |
| `jitter_3d.py` | 3D animation with radial breathing |
| `cube_flow.py` | Topology-changing vertex flow animation |
| `ddg_dual_1d.py` | 1D dual mesh (midpoint) |
| `ddg_dual_2d.py` | 2D dual mesh (barycentric vs circumcentric) |
| `ddg_dual_3d.py` | 3D dual mesh with polyscope |
| `ddg_dual_4d.py` | 4D dual mesh (stats/verification, no visualization) |
| `disconnectivity_graph_1D.py` | 1D energy landscape barrier tree |
| `disconnectivity_graph.py` | 2D multi-basin disconnectivity graph |
| `bench_ddg.py` | DDG benchmarks across dims/methods/refinement levels |
