cartan

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

Definition null (Riemannian Manifold).

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>;
}
Implemented by: Sphere<N>, Euclidean<N>, SO<N>, SE<N>, SPD<N>, Grassmann<N,K>

Exponential Map

Definition null (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|$.

Example ?: Sphere exp; great circle walk

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.

Remark null.

$\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

Definition null (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);

Implemented By