Testing#
GeoJAX uses deterministic numerical tests, executable documentation, and clean package installation checks. A release should pass the complete matrix rather than only the maintainer’s active Python environment.
Current environment#
Check style and run both JAX precision modes before committing:
make quality
make test
make test-float32
Both commands execute the full test suite with branch coverage. Coverage below
85 percent fails the run. GEOJAX_TEST_X64 is set by these targets so tests do
not silently inherit a developer’s JAX configuration.
Invariant assertions keep their original strict float64 tolerances. In float32, tests add a small dtype-aware allowance for decomposition roundoff and avoid perturbations below machine resolution. This preserves the mathematical assertion instead of expecting float32 arithmetic to reproduce a float64 residual.
Numerical stability#
Every public geometry is exercised with unbatched, nested-batch, and broadcast-base inputs. The stability suite differentiates exponential maps at zero tangents, logarithms and squared distances at coincident points, and SPD matrix functions at repeated eigenvalues. Directional finite differences independently check representative JVPs away from cut loci.
Contract tests additionally project zero, noisy, indefinite, and rank-deficient ambient inputs and require the repaired value to pass membership. Malformed event dimensions must fail before an operation can silently run on a different manifold. Float32 tests explicitly check open-ball margins and the active spectral floors used by SPD and fixed-rank repairs.
Second-order tests verify known Riemannian Hessian identities, including the
sphere shape-operator term, and require unsupported automatic conversions to
fail with an explicit request for rhess_vec.
Genuine singularities have separate regression tests. In particular, a spherical antipode retains a finite distance but an explicitly nonfinite logarithm and transport.
The learning release contract compiles complete deterministic-autoencoder steps with spherical and hyperbolic latents. It requires decreasing reconstruction loss, finite encoder gradients, and valid manifold points after training. Learning-helper tests also combine vector-valued interpolation times with batched endpoints and reject proxy distances or logarithms where the public helper promises an exact geodesic operation.
The release suite enforces two branch-aware coverage thresholds: at least 85%
repository-wide and at least 95% for geojax.learning. Both reports come from
the same complete run, so adapter failures, statistical edge cases, and
optional-integration boundaries remain part of the release contract.
Supported matrix#
Install the development dependencies and run:
python -m pip install -e ".[dev]"
make test-matrix
The first run downloads managed CPython interpreters through tox-uv.
Subsequent runs reuse those interpreters and isolated tox environments. Tox
uses managed interpreters even when a matching conda or system Python happens
to be active, making the matrix independent of a developer’s base
environment. Missing versions are errors; they are never silently skipped.
The supported minor versions also live in .python-versions, so
uv python install can prepare all of them directly.
Each tox environment builds a wheel, changes to an isolated temporary working
directory, clears pytest’s source-tree pythonpath, and asserts that
import geojax resolves inside that environment. The matrix therefore tests
the installed artifact rather than accidentally importing the checkout.
Installed module contents must also match the source exactly.
The runner starts a fresh process for each test file, so JAX compilation caches
cannot accumulate across the complete suite. It records the collected tests,
execution results, timings, and source hashes, then combines coverage before
enforcing the global and learning thresholds. Every test file is required;
an unexplained empty collection, incomplete run, failure, or timeout fails the
environment. Each file has a 600-second wall limit enforced by its parent
process. A timed-out worker receives a stack-snapshot request before
termination. Background traceback timers are disabled: a CPython watchdog
was observed blocking pytest after a completed test. Reports are retained in
timestamped subdirectories under .tox/verification/<environment>/.
For a faster laptop run with bounded and coverage-safe concurrency:
make test-matrix-parallel
The default is two workers. Override it only when the machine has enough CPU
and memory, for example make test-matrix-parallel TOX_PARALLEL=3.
The release-blocking matrix is pinned and covers:
Python |
Dependencies |
JAX precision |
|---|---|---|
3.11 |
JAX 0.6.0 and NumPy 1.26.4 |
float32, float64 |
3.11 |
JAX 0.10.2 and NumPy 2.4.4 |
float32, float64 |
3.12 |
JAX 0.11.0 and NumPy 2.4.4 |
float32, float64 |
3.13 |
JAX 0.11.0 and NumPy 2.4.4 |
float32, float64 |
3.14 |
JAX 0.11.0 and NumPy 2.4.4 |
float32, float64 |
The lower-bound environments guard the oldest runtime versions promised by
pyproject.toml. Stable environments pin JAX, JAXlib, NumPy, SciPy,
ml-dtypes, opt-einsum, pytest, and coverage tooling, preventing a new
upstream release from changing an otherwise identical release check. Update
these pins deliberately, then run the complete matrix before merging the
change. Coverage data is stored separately for every environment and run, so
sequential and modestly parallel runs have the same isolation guarantees.
GitHub CI runs all ten pinned combinations above with the same complete-suite runner and uploads the reports even when a job fails. It also runs quality checks, rebuilds the documentation, and installs both generated package formats outside the checkout.
Completed correctness audit#
The 25 September 2026 audit of commit b7361be passed all ten complete
installed-wheel environments: 11,465 test executions passed, with 15 expected
skips. Branch-aware coverage exceeded the 85% global and 95% learning
thresholds in every environment. A separate 140-test supplement passed with
JAX 0.11.2 and the real optional OTT backend, with no skips.
Independent mathematical and statistical cross-checks passed, and all 25 documentation notebooks and 97 code cells executed successfully. This validation used macOS ARM64 CPU; GPU and TPU execution remain untested. The complete audit report records the corrections, reproducible evidence, and remaining numerical and statistical limitations.
Documentation#
make website
This executes every MyST Markdown tutorial from a clean Sphinx environment,
treats Sphinx warnings and execution errors as build failures, and audits
rendered mathematics and local references. jupyter_execute/ and
.jupyter_cache/ are transient: the build deletes both after the HTML audit
succeeds. The .md tutorial is always the maintained source.
Release candidate#
make release-check
The release target requires the complete tox matrix, rebuilds every tutorial, creates clean wheel and source archives, applies Twine’s strict metadata validation, and installs both artifacts from a temporary directory. It first requires a clean commit carrying the annotated version tag, then checks the source again after documentation generation and before packaging. Tutorial execution can regenerate tracked figures, so those changes must be reviewed and committed before tagging the release. The target prints the SHA-256 digest of each artifact. It does not upload or publish anything.