cartan

Retraction

A retraction is a computationally cheaper alternative to the exponential map for optimization on manifolds. It sacrifices the geodesic property but retains first-order accuracy; sufficient for gradient descent and line search.

Definition

Definition null (Retraction).

A retraction on $M$ is a smooth map $R : TM \to M$ such that for each $p \in M$ the restriction $R_p : T_pM \to M$ satisfies:

  1. Consistency: $R_p(0) = p$
  2. Local rigidity:

Condition 2 means $R_p$ agrees with $\exp_p$ to first order at $p$.

The key implication: using $R$ instead of $\exp$ in Riemannian gradient descent preserves the convergence guarantees while cutting the per-step cost significantly (no transcendental function evaluations on most manifolds).

The Retraction Trait

pub trait Retraction: Manifold {
  fn retract(&self, p: &Self::Point, v: &Self::Tangent) -> Self::Point;
  fn inverse_retract(
      &self,
      p: &Self::Point,
      q: &Self::Point,
  ) -> Option<Self::Tangent>;
}
Implemented by: Sphere<N>, Euclidean<N>, SO<N>, SE<N>, SPD<N>, Grassmann<N,K>

Every type that implements Manifold automatically gets a blanket implementation via exp/log, so you only need a custom impl when a cheaper retraction exists.

Blanket Implementation

// Provided automatically; no work needed.
impl<M: Manifold> Retraction for M {
    fn retract(&self, p: &Self::Point, v: &Self::Tangent) -> Self::Point {
        self.exp(p, v)
    }
    fn inverse_retract(&self, p: &Self::Point, q: &Self::Point) -> Option<Self::Tangent> {
        self.log(p, q)
    }
}

Override this for manifolds where a cheaper retraction exists.

Example: Sphere Projection Retraction

On the projection retraction is:

This costs one vector addition and one normalization; no sin/cos calls.

Example ?: Projection retraction vs exp on S²

Both return a point on $S^2$. The projection retraction drifts slightly from the true geodesic endpoint for large steps, but both satisfy the retraction axioms.

use cartan::prelude::*;
use cartan::manifolds::Sphere;
 
let s2 = Sphere::<3>;
let p  = s2.random_point(&mut rand::rng());
let v  = s2.random_tangent(&p, &mut rand::rng());
 
let q_exact = s2.exp(&p, &v);           // exact geodesic
let q_retract = s2.retract(&p, &v);     // projection (cheaper)
 
// Both lie on S²:
assert!((q_exact.norm() - 1.0).abs() < 1e-12);
assert!((q_retract.norm() - 1.0).abs() < 1e-12);
 
// They agree to first order near p:
let small_v = v * 0.001;
let q1 = s2.exp(&p, &small_v);
let q2 = s2.retract(&p, &small_v);
assert!((q1; q2).norm() < 1e-8);

Inverse Retraction

inverse_retract(p, q) computes the tangent $v$ such that $R_p(v) = q$. Returns None at the cut locus (same as log). Used by optimizers that need to measure displacement in tangent space coordinates.

When to Use a Custom Retraction

ManifoldExp costProjection retraction cost
Spheresin, cosnormalize (1 sqrt)
SO(N)matrix exponential $O(N^3)$QR decomposition $O(N^3)$, smaller constant
SPD(N)symmetric matrix expCholesky-based, cheaper constant
Euclideantrivialtrivial (same as exp)

For large-scale optimization (e.g. fitting a Fréchet mean over thousands of points), a 2× retraction speedup compounds over many gradient steps.