Manifold
A Riemannian manifold is a smooth manifold equipped with a continuously varying
inner product on each tangent space. cartan represents every manifold as a
zero-sized struct implementing the Manifold trait.
Definition
A Riemannian manifold is a pair $(M, g)$ where $M$ is a smooth manifold and is a Riemannian metric, a smooth assignment of an inner product to each tangent space $T_pM$.
In cartan every manifold is represented extrinsically: points live in an
ambient Euclidean space and tangent vectors are vectors in that space
satisfying a constraint (e.g. $p^\top v = 0$ on the sphere).
The Manifold Trait
pub trait Manifold: Sized + Send + Sync {
/// Ambient dimension N (const generic).
const AMBIENT_DIM: usize;
/// Intrinsic dimension n = dim M.
const DIM: usize;
type Point: Clone + Send + Sync;
type Tangent: Clone + Send + Sync;
// ── metric ──────────────────────────────────────────────────
fn inner(&self, p: &Self::Point, u: &Self::Tangent, v: &Self::Tangent) -> f64;
fn norm(&self, p: &Self::Point, v: &Self::Tangent) -> f64 {
self.inner(p, v, v).sqrt()
}
// ── geodesic maps ────────────────────────────────────────────
fn exp(&self, p: &Self::Point, v: &Self::Tangent) -> Self::Point;
fn log(&self, p: &Self::Point, q: &Self::Point) -> Option<Self::Tangent>;
fn dist(&self, p: &Self::Point, q: &Self::Point) -> f64;
// ── projections ──────────────────────────────────────────────
fn project_tangent(&self, p: &Self::Point, v: &Self::Tangent) -> Self::Tangent;
fn project_point(&self, x: &Self::Point) -> Self::Point;
// ── sampling ─────────────────────────────────────────────────
fn random_point(&self, rng: &mut impl Rng) -> Self::Point;
fn random_tangent(&self, p: &Self::Point, rng: &mut impl Rng) -> Self::Tangent;
// ── validation ───────────────────────────────────────────────
fn check_point(&self, p: &Self::Point) -> Result<(), CartanError>;
fn check_tangent(&self, p: &Self::Point, v: &Self::Tangent) -> Result<(), CartanError>;
}Sphere<N>, Euclidean<N>, SO<N>, SE<N>, SPD<N>, Grassmann<N,K>Exponential Map
For $p \in M$ and $v \in T_pM$, the exponential map $\exp_p(v)$ is the point reached by following the unique geodesic $\gamma$ with $\gamma(0) = p$, $\dot\gamma(0) = v$ for unit time:
When $|v| = r$, the geodesic travels distance $r$ from $p$ along the direction $v / |v|$.
On with ambient dimension $N$, the exponential map is:
For $v = 0$ we get $\exp_p(0) = p$ (identity). For $|v| = \pi$, we reach the antipodal point $-p$.
Logarithmic Map
The logarithmic map $\log_p : M \to T_pM$ is the inverse of $\exp_p$. It returns the initial tangent vector whose geodesic reaches $q$ at time 1.
$\log_p(q)$ is undefined when $q$ lies on the cut locus of $p$, the set of
points where geodesics from $p$ stop being uniquely length-minimizing. For the
sphere, the cut locus of $p$ is its antipodal point . cartan returns
None at the cut locus.
// Always handle the None case.
match manifold.log(&p, &q) {
Some(v) => println!("tangent vector: {:?}", v),
None => println!("q is on the cut locus of p"),
}Riemannian Metric
The Riemannian metric at $p$ is a smooth, symmetric, positive-definite bilinear
form . In cartan this is exposed as:
fn inner(&self, p: &Self::Point, u: &Self::Tangent, v: &Self::Tangent) -> f64;For Sphere<N> and Euclidean<N>, the metric is the standard Euclidean dot
product restricted to the tangent space. For SO<N> it is the bi-invariant
metric .
Projections
Working in extrinsic coordinates requires two projections:
project_tangent(p, v): removes the normal component of an ambient vector
to produce a vector in $T_pM$. On the sphere:
$\Pi_p(v) = v - (p^\top v),p$.
project_point(x): maps an ambient point onto $M$
(e.g. $x \mapsto x / |x|$ for the sphere). Used after small perturbations that
may drift off the manifold.
Validation
// Check that p lies on M within tolerance.
manifold.check_point(&p)?;
// Check that v is in T_pM within tolerance.
manifold.check_tangent(&p, &v)?;Both return Err(CartanError::PointNotOnManifold) or
Err(CartanError::NotATangentVector) on failure. See
Error Handling →.
Random Sampling
let mut rng = rand::rng();
// Uniform point on M (Haar measure for Lie groups).
let p = manifold.random_point(&mut rng);
// Unit tangent vector at p (uniform on unit sphere in T_pM).
let v = manifold.random_tangent(&p, &mut rng);