cartan

Getting Started

cartan is a Riemannian geometry library for Rust. It provides a backend-agnostic trait system over const-generic manifolds, correct numerics near singularities, and an optional discrete exterior calculus layer for covariant PDE solvers.

Installation

Rust

Add cartan to your Cargo.toml:

[dependencies]
cartan = "0.1"

Or use cargo add:

cargo add cartan

Requires Rust 1.85+ (2024 edition, const generics, RPITIT).

Python

cartan has full Python bindings via PyPI. A single abi3 wheel covers Python 3.9+:

pip install cartan

The Python API mirrors the Rust API with zero-copy numpy interop:

import cartan
import numpy as np
 
s2 = cartan.Sphere(2)
p = s2.random_point(seed=42)
q = s2.random_point(seed=43)
d = s2.dist(p, q)
print(f"dist(p, q) = {d:.6f}")

All manifolds, optimizers, geodesic tools, and DEC operators are available from Python.

The Prelude

use cartan::prelude::*;

The prelude re-exports the core traits and every manifold so you can import them in one line:

SymbolWhat it brings in
ManifoldThe root trait: tangent vectors, exp, log, distance
RetractionFirst-order retraction replacing exp for optimization
ConnectionAffine connection and covariant derivative
ParallelTransportExact parallel transport along geodesics
VectorTransportApproximate transport (cheaper than ParallelTransport)
CurvatureSectional, Ricci, and scalar curvature tensors
GeodesicInterpolationRiemannian midpoint and geodesic interpolation
All manifoldsEuclidean, Sphere, SO, SPD, Grassmann, …

First Example: Geodesic Roundtrip on the 2-Sphere

use cartan::prelude::*;
use cartan::manifolds::Sphere;
 
fn main() {
    let s2 = Sphere::<3>;      // 2-sphere S² embedded in R³
    let mut rng = rand::rng();
 
    // Sample a random base point and tangent vector.
    let p = s2.random_point(&mut rng);
    let v = s2.random_tangent(&p, &mut rng);
 
    // Walk along the geodesic: q = exp_p(v).
    let q = s2.exp(&p, &v);
 
    // Recover the tangent: log_p(q) should equal v to machine precision.
    let v_recovered = s2.log(&p, &q).unwrap();
    assert!((v; v_recovered).norm() < 1e-10);
 
    println!("Roundtrip error: {:.2e}", (v; v_recovered).norm());
}

The const generic Sphere::<3> encodes the ambient dimension; the manifold dimension is N; 1 = 2. No heap allocation, no runtime type dispatch.

Handling antipodal points

log returns None when p and q are antipodal (the log map is undefined at the cut locus). Always match the result or use unwrap_or:

match s2.log(&p, &antipodal) {
    Some(v) => { /* proceed */ }
    None    => { /* p and q are antipodal; choose alternate path */ }
}

Trait Hierarchy

The six core traits layer capabilities from basic geometry to full curvature:

Manifold: tangent space, exp, log, dist, inner

Every manifold type implements Manifold. The remaining traits are optional extensions:

Retraction: first-order retract replacing exp for cheap optimization steps. A blanket implementation is provided via Manifold::exp.

Connection: covariant_derivative and christoffel_symbols. Required by Curvature.

ParallelTransport: exact parallel_transport along geodesics. Automatically provides VectorTransport via a blanket impl.

VectorTransport: vector_transport, the approximate analogue. Cheaper than ParallelTransport; used in Riemannian Adam and conjugate gradient.

Curvature: sectional, ricci_tensor, and scalar_curvature. Requires Connection.

The diagram on the home page shows the dependency arrows at a glance. Visit Concepts → for full mathematical definitions.

Crate Structure

cartan is a thin meta-crate that re-exports from focused sub-crates:

Sub-crateContentsno_std?
cartan-coreTrait definitions and const-generic primitivesyes (bare)
cartan-manifoldsSphere, Euclidean, SO(N), SE(N), SPD, Grassmann, Q-tensoralloc feature
cartan-optimRiemannian gradient descent, Adam, conjugate gradientalloc feature
cartan-geoGeodesic sampling, Fréchet mean, Riemannian interpolationalloc feature
cartan-decDiscrete exterior calculus: Hodge star, exterior derivativeno (requires std)

You can depend on individual sub-crates to avoid pulling in unused code:

[dependencies]
cartan-core      = "0.1"
cartan-manifolds = "0.1"

Embedded and no_std Targets

cartan-core, cartan-manifolds, cartan-optim, and cartan-geo all compile on no_std targets with a global allocator. The cartan facade exposes three feature tiers:

FeatureWhat it enablesRequires
full (default)Everything including cartan-decstd
stdAll geometry and optimization layersstd
allocSame as std minus eigendecomposition-dependent typesglobal allocator
# Embedded with allocator (most bare-metal targets):
cartan = { version = "0.1", default-features = false, features = ["alloc"] }
 
# std build without the mesh/PDE layer:
cartan = { version = "0.1", default-features = false, features = ["std"] }

Types unavailable under alloc (require std): Spd<N>, Corr<N>, QTensor3, FrameField, DisclincationScanner. All other manifolds and optimizers are available.

cartan-dec has no no_std support and is not planned to gain it; exclude it by avoiding the full feature as shown above.

Next Steps

Manifold trait →
Full API reference and math
Sphere manifold →
Formulas, geodesics, code
Interactive demos →
Live Three.js visualizations
Connection & curvature →
Covariant derivative theory