API Reference
Core Concepts
Core C++20 concepts defining the manifold interface hierarchy.
HasMetric concept and batched variant for manifolds with a Riemannian inner product.
HasDistance concept for manifolds with geodesic distance.
HasGeodesic concept for manifolds with geodesic interpolation and exp/log maps.
Retraction concept for generalized exponential/logarithmic maps.
Manifolds
Sphere
-
template<int Dim = 2, typename MetricT = IdentityMetric<detail::sphere_ambient_v<Dim>>, typename RetractionT = SphereExponentialMap, typename SamplerT = StochasticSampler>
class Sphere The n-sphere \( S^n \) parameterized by dimension, metric and retraction.
This class composes a metric policy and a retraction policy to form a complete
RiemannianManifold. Points are represented as unit vectors in \( \mathbb{R}^{n+1} \); tangent vectors live in the orthogonal complement of the base point.- Template Parameters:
Dim – Intrinsic dimension (e.g.
2for \( S^2 \)), orEigen::Dynamicfor runtime sizing. Defaults to2(the classical round 2-sphere).MetricT – Metric policy (default:
ConstantSPDMetric<Dim+1>identity).RetractionT – Retraction policy (default:
SphereExponentialMap).
Metric delegates
Retraction delegates
Derived operations
-
inline Scalar distance(const Point &p, const Point &q) const
Geodesic distance \( d(p, q) \) via the midpoint approximation.
- Parameters:
p – First point on the sphere.
q – Second point on the sphere.
- Returns:
The geodesic distance.
-
inline Scalar injectivity_radius() const
Injectivity radius of the round n-sphere: \( \pi \).
Returns the topological injectivity radius for the default round (identity) metric. For anisotropic custom metrics the effective radius is smaller: \( \pi / \sqrt{\lambda_{\max}(A)} \) where \( \lambda_{\max} \) is the largest eigenvalue of the weight matrix. This value is an upper bound;
discrete_geodesicuses it for step capping and may take extra retries if the true radius is smaller.
Public Types
-
using Scalar = double
Scalar type.
Public Functions
-
inline bool has_riemannian_log_runtime() const
Runtime query: is
logthe Riemannian logarithm of the metric?Only when the metric is the identity
ConstantSPDMetric<Ambient>AND the retraction is the true exponential map doesgrad((1/2) d^2)(x) = -log_x(q)hold exactly. Other metrics and any projection retraction fall back to finite-difference natural gradient.
-
inline Sphere()
Static-dim default constructor: default-construct metric/retraction.
-
inline explicit Sphere(MetricT metric, RetractionT retraction = {})
Static-dim constructor with explicit metric and retraction policies.
-
inline explicit Sphere(int n)
Dynamic-dim constructor: takes the intrinsic dimension \( n \) of \( S^n \).
-
inline Sphere(int n, MetricT metric, RetractionT retraction = {})
Dynamic-dim constructor with explicit metric and retraction.
-
inline int dim() const
Return the intrinsic dimension \( n \) of \( S^n \).
-
inline Point random_point() const
Sample a uniformly random point on \( S^n \).
Draws
n+1uniform samples from the sampler viasample_box, applies the Box-Muller transform to produce standard normal variates, and normalizes the resulting vector to project onto the sphere. This is mathematically equivalent to Marsaglia’s method but uses the configurable sampler policy instead of a thread-local RNG.- Returns:
A unit vector in \( \mathbb{R}^{n+1} \).
-
using geodex::SphereRoundMetric = IdentityMetric<3>
The standard round (bi-invariant) metric on \( S^2 \).
The inner product is the ambient Euclidean dot product restricted to tangent vectors: \( \langle u, v \rangle_p = u \cdot v \). Zero-storage stateless metric.
-
struct SphereExponentialMap
True exponential and logarithmic maps on \( S^n \) (round geometry).
retract(p, v)computes \( \exp_p(v) = \cos(\|v\|)\, p + \sin(\|v\|)\, v / \|v\| \)inverse_retract(p, q)computes \( \log_p(q) \) via the arc-length formula
Both methods are polymorphic in the point type, so the same retraction struct serves every \( S^n \).
Public Functions
- template<typename Point> inline EIGEN_STRONG_INLINE Point retract (const Point &p, const Point &v) const
Exponential map \( \exp_p(v) \) on \( S^n \).
- Parameters:
p – Base point on the sphere.
v – Tangent vector at \( p \).
- Returns:
The resulting point on the sphere.
- template<typename Point> inline EIGEN_STRONG_INLINE Point inverse_retract (const Point &p, const Point &q) const
Logarithmic map \( \log_p(q) \) on \( S^n \).
- Parameters:
p – Base point on the sphere.
q – Target point on the sphere.
- Returns:
Tangent vector at \( p \) such that \( \exp_p(v) = q \).
-
struct SphereProjectionRetraction
First-order projection retraction on \( S^n \).
retract(p, v)computes \( R_p(v) = (p + v) / \|p + v\| \)inverse_retract(p, q)projects \( q - p \) onto \( T_p S^n \)
Public Functions
- template<typename Point> inline EIGEN_STRONG_INLINE Point retract (const Point &p, const Point &v) const
Projection retraction: normalize \( p + v \).
- Parameters:
p – Base point on the sphere.
v – Tangent vector at \( p \).
- Returns:
The retracted point on the sphere.
- template<typename Point> inline EIGEN_STRONG_INLINE Point inverse_retract (const Point &p, const Point &q) const
Inverse projection retraction.
- Parameters:
p – Base point on the sphere.
q – Target point on the sphere.
- Returns:
Tangent vector at \( p \) approximating \( \log_p(q) \).
Euclidean
-
template<int Dim = Eigen::Dynamic, typename MetricT = EuclideanStandardMetric<Dim>, typename SamplerT = StochasticSampler>
class Euclidean Euclidean manifold \( \mathbb{R}^n \) parameterized by dimension and metric policy.
Supports both compile-time fixed dimension (e.g.,
Euclidean<3>) and runtime dynamic dimension (Euclidean<Eigen::Dynamic>). The exp/log maps are trivial (addition/subtraction) since the space is flat.- Template Parameters:
Dim – Compile-time dimension, or
Eigen::Dynamic.MetricT – Metric policy (default: EuclideanStandardMetric).
SamplerT – Sampler policy for
random_point()(default:StochasticSampler).
Metric delegates
Exp / Log
Derived operations
-
inline Scalar distance(const Point &p, const Point &q) const
Geodesic distance via the midpoint approximation.
- Parameters:
p – First point.
q – Second point.
- Returns:
The distance \( d(p, q) \).
-
inline Scalar injectivity_radius() const
Injectivity radius of \( \mathbb{R}^n \): \( \infty \).
Euclidean space is flat, so the injectivity radius is infinite regardless of the metric. Anisotropic custom metrics change geodesic directions but not the fact that the space is simply connected and geodesically complete.
Public Types
-
using Scalar = double
Scalar type.
Public Functions
-
inline bool has_riemannian_log_runtime() const
Runtime query: is
logthe Riemannian logarithm of the metric?True only when the metric is the identity
ConstantSPDMetric<Dim>(the standard Euclidean dot product). Non-identity SPDs live under a different inner product, sodiscrete_geodesicfalls back to finite differences for those cases.
-
inline Euclidean()
Fixed-dimension constructor with default bounds \([-1, 1]^n\).
-
inline explicit Euclidean(MetricT metric)
Fixed-dimension constructor with custom metric.
- Parameters:
metric – The metric policy instance.
-
inline explicit Euclidean(int n)
Dynamic-dimension constructor.
- Parameters:
n – The dimension of the space.
-
inline Euclidean(int n, MetricT metric)
Dynamic-dimension constructor with custom metric.
- Parameters:
n – The dimension of the space.
metric – The metric policy instance.
-
inline void set_sampling_bounds(const Eigen::VectorXd &lo, const Eigen::VectorXd &hi)
Set the sampling bounds.
Values outside these bounds are never returned by
random_point(), butexp/log/metric operations remain unchanged (bounds are a sampler concern, not a topological one).
-
inline int dim() const
Return the dimension of the space.
-
inline Point random_point() const
Sample a point uniformly in \([\mathrm{lo}, \mathrm{hi}]^n\) (default \([-1, 1]^n\)).
Uses the configured
SamplerT(default:StochasticSampler) to draw uniform box samples and linearly rescales to the sampling bounds. PassHaltonSamplervia the template parameter for deterministic low-discrepancy sampling.
-
template<int Dim = Eigen::Dynamic>
using geodex::EuclideanStandardMetric = IdentityMetric<Dim> The standard Euclidean metric on \( \mathbb{R}^n \).
The inner product is the standard dot product: \( \langle u, v \rangle = u \cdot v \). Zero-storage stateless metric.
Torus
-
template<int Dim = Eigen::Dynamic, typename MetricT = TorusFlatMetric<Dim>, typename SamplerT = StochasticSampler>
class Torus Flat torus \( T^n \) parameterized by dimension and metric policy.
Points are represented as angles in \( [0, 2\pi)^n \). The exp map wraps to \( [0, 2\pi) \) and the log map wraps differences to \( [-\pi, \pi) \).
- Template Parameters:
Dim – Compile-time dimension, or
Eigen::Dynamic.MetricT – Metric policy (default: TorusFlatMetric).
SamplerT – Sampler policy for
random_point()(default:StochasticSampler).
Metric delegates
Exp / Log
Derived operations
-
inline Scalar distance(const Point &p, const Point &q) const
Geodesic distance via the midpoint approximation.
- Parameters:
p – First point.
q – Second point.
- Returns:
The distance \( d(p, q) \).
-
inline Scalar injectivity_radius() const
Injectivity radius of \( T^n \): \( \pi \) (half the period).
Returns the topological value for the default identity metric and period \( 2\pi \). For anisotropic custom metrics the effective radius is \( \pi / \sqrt{\lambda_{\max}(A)} \). This value is an upper bound;
discrete_geodesicmay take extra retries if the true radius is smaller.
Public Types
-
using Scalar = double
Scalar type.
Public Functions
-
inline bool has_riemannian_log_runtime() const
Runtime query: is
logthe Riemannian logarithm of the metric?Torus topology has trivial exp/log (addition/wrapping), which is the Riemannian log exactly when the metric is the identity (standard flat metric). Anisotropic SPDs are still flat in the mathematical sense but their geodesics are reparameterized, so we mark them as not log-compatible and
discrete_geodesicuses finite differences.
-
inline Torus()
Fixed-dimension constructor.
-
inline explicit Torus(MetricT metric)
Fixed-dimension constructor with custom metric.
- Parameters:
metric – The metric policy instance.
-
inline explicit Torus(int n)
Dynamic-dimension constructor.
- Parameters:
n – The dimension of the torus.
-
inline Torus(int n, MetricT metric)
Dynamic-dimension constructor with custom metric.
- Parameters:
n – The dimension of the torus.
metric – The metric policy instance.
-
inline int dim() const
Return the dimension of the torus.
-
template<int Dim = Eigen::Dynamic>
using geodex::TorusFlatMetric = IdentityMetric<Dim> Standard flat metric on \( T^n \).
The inner product is the standard dot product: \( \langle u, v \rangle = u \cdot v \). Zero-storage stateless metric.
SE(2)
-
template<typename MetricT = SE2LeftInvariantMetric, typename RetractionT = SE2ExponentialMap, typename SamplerT = StochasticSampler>
class SE2 The special Euclidean group \( \mathrm{SE}(2) = \mathbb{R}^2 \rtimes \mathrm{SO}(2) \).
Poses are represented as \( (x, y, \theta) \) with \( \theta \in [-\pi, \pi) \). The manifold is parameterized by a metric policy and a retraction policy, following the same design as Sphere and Torus.
- Template Parameters:
MetricT – Metric policy (default: SE2LeftInvariantMetric).
RetractionT – Retraction policy (default: SE2ExponentialMap).
SamplerT – Sampler policy for
random_point()(default:StochasticSampler).
Metric delegates
Retraction delegates
Derived operations
Public Types
-
using Scalar = double
Scalar type.
-
using Point = Eigen::Vector3d
Pose \( (x, y, \theta) \).
-
using Tangent = Eigen::Vector3d
Tangent vector \( (v_x, v_y, \omega) \).
Public Functions
-
inline bool has_riemannian_log_runtime() const
Runtime query: is the currently-configured metric the bi-invariant Lie group metric (unit weights on
SE2LeftInvariantMetricpaired with the trueSE2ExponentialMap)?Only in this case is the Lie-group
logthe Riemannian logarithm of the metric, sodiscrete_geodesiccan safely take the log direction as the natural gradient.discrete_geodesiccalls this method to activate the fast path on a per-call basis — anisotropic SE2 metrics fall through to finite differences.Because
SE2LeftInvariantMetric::weights_is a runtime value, this check cannot be made at compile time.
-
SE2() = default
Default constructor.
Users must call
set_sampling_bounds()before usingrandom_point()if the default \([0,10]^2 \times [-\pi,\pi)\) is unsuitable.
-
inline explicit SE2(MetricT metric)
Construct with explicit metric.
- Parameters:
metric – The metric policy instance.
-
inline SE2(const Eigen::Vector3d &lo, const Eigen::Vector3d &hi)
Construct with sampling bounds.
- Parameters:
lo – Lower sampling bounds \((x_\min, y_\min, \theta_\min)\).
hi – Upper sampling bounds \((x_\max, y_\max, \theta_\max)\).
-
inline SE2(MetricT metric, const Eigen::Vector3d &lo, const Eigen::Vector3d &hi)
Construct with explicit metric and sampling bounds.
- Parameters:
metric – The metric policy instance.
lo – Lower sampling bounds \((x_\min, y_\min, \theta_\min)\).
hi – Upper sampling bounds \((x_\max, y_\max, \theta_\max)\).
-
inline SE2(MetricT metric, RetractionT retraction, const Eigen::Vector3d &lo, const Eigen::Vector3d &hi)
Construct with explicit metric, retraction, and sampling bounds.
- Parameters:
metric – The metric policy instance.
retraction – The retraction policy instance.
lo – Lower sampling bounds \((x_\min, y_\min, \theta_\min)\).
hi – Upper sampling bounds \((x_\max, y_\max, \theta_\max)\).
-
inline void set_sampling_bounds(const Eigen::Vector3d &lo, const Eigen::Vector3d &hi)
Set the sampling bounds.
-
inline int dim() const
Return the intrinsic dimension (always 3).
Configuration Space
-
template<typename BaseManifoldT, typename MetricT>
class ConfigurationSpace A configuration space that combines a base manifold’s topology with a custom Riemannian metric.
Only topology operations (exp, log, random_point, dim) are delegated to the base manifold. All geometry (inner, norm, distance) comes from
MetricT. The base manifold’s own metric is never called by this class — it exists only because the base must be a completeRiemannianManifold(which requires exp/log).- Template Parameters:
BaseManifoldT – The base manifold type (must provide exp, log, dim, random_point).
MetricT – The metric policy type (must provide
innerandnorm).
Topology — delegated to base manifold
-
inline int dim() const
Return the intrinsic dimension.
-
inline Point exp(const Point &p, const Tangent &v) const
Exponential map (or retraction) from the base manifold.
Geometry — delegated to custom metric
-
inline Scalar inner(const Point &p, const Tangent &u, const Tangent &v) const
Riemannian inner product from the custom metric.
-
inline Eigen::MatrixXd inner_matrix(const Point &p, const Eigen::MatrixXd &U, const Eigen::MatrixXd &V) const
Batched inner product \(U^\top M(p)\, V\) when the custom metric provides it.
Forwards to the metric’s
inner_matrix. This is the main performance hook for kinetic-energy configuration spaces, where the expensive mass matrix evaluation is amortized over all \(d^2\) entries of the tangent-metric tensor in a single call.
Derived operations
-
inline Scalar distance(const Point &p, const Point &q) const
Geodesic distance via the midpoint approximation.
Public Types
-
using Scalar = typename BaseManifoldT::Scalar
Scalar type from the base manifold.
-
using Point = typename BaseManifoldT::Point
Point type from the base manifold.
-
using Tangent = typename BaseManifoldT::Tangent
Tangent vector type from the base manifold.
Public Functions
-
inline bool has_riemannian_log_runtime() const
Runtime query: is
logthe Riemannian logarithm of the custom metric?Always returns
false. The whole purpose ofConfigurationSpaceis to overlay a custom metric on a base manifold — the base’slogis the Riemannian log of the base’s native metric, not of the custom metric. This forcesdiscrete_geodesicto use the finite-difference natural gradient, which correctly follows the energy-minimizing curve under the custom metric.Warning
Setting
InterpolationSettings::force_log_direction = trueon a ConfigurationSpace bypasses this and uses the base manifold’s log for direction. The resulting path follows the base metric’s geodesic, not the custom metric’s. Only use when the base log is a reasonable approximation.
-
inline ConfigurationSpace(BaseManifoldT base, MetricT metric)
Construct with a base manifold and a metric.
- Parameters:
base – The base manifold instance.
metric – The metric policy instance.
-
inline const BaseManifoldT &base() const
Access the base manifold.
Metrics
-
template<int Dim = Eigen::Dynamic>
class IdentityMetric Stateless identity metric: \( \langle u, v \rangle_p = u \cdot v \).
A zero-storage alternative to
ConstantSPDMetric<Dim>with the identity weight matrix. Uses O(1) memory instead of O(n^2) for the identity-metric case. All manifold default-metric aliases (SphereRoundMetric,TorusFlatMetric,EuclideanStandardMetric) point here.- Template Parameters:
Dim – Compile-time vector dimension, or
Eigen::Dynamic.
Public Functions
-
inline double inner(const Eigen::Vector<double, Dim>&, const Eigen::Vector<double, Dim> &u, const Eigen::Vector<double, Dim> &v) const
Compute the inner product \( \langle u, v \rangle = u \cdot v \).
- Parameters:
u – First tangent vector.
v – Second tangent vector.
- Returns:
The inner product value.
-
inline double norm(const Eigen::Vector<double, Dim> &p, const Eigen::Vector<double, Dim> &v) const
Compute the norm \( \|v\| = \sqrt{v \cdot v} \).
- Parameters:
p – Base point (unused).
v – Tangent vector.
- Returns:
The norm value.
-
inline Eigen::MatrixXd inner_matrix(const Eigen::Vector<double, Dim>&, const Eigen::MatrixXd &U, const Eigen::MatrixXd &V) const
Batched inner product: \( U^\top V \).
-
inline Eigen::MatrixXd weight_matrix() const
Identity weight matrix (runtime-sized identity, for API compatibility).
Returns a dynamically-sized identity matrix of the given dimension. Provided so that
has_riemannian_log_runtime()can callweight_matrix()uniformly on any metric. UnlikeConstantSPDMetric, this allocates only when called — which should be rare.
-
template<int Dim = Eigen::Dynamic>
class ConstantSPDMetric Point-independent Riemannian metric defined by a constant SPD matrix.
The inner product is \( \langle u, v \rangle_p = u^\top A \, v \) where \( A \) is a symmetric positive-definite matrix. The metric does not depend on the base point \( p \).
This is a manifold-agnostic metric: the same class works for spheres, Euclidean spaces, tori, or any manifold whose tangent vectors are Eigen column vectors.
- Template Parameters:
Dim – Compile-time dimension, or
Eigen::Dynamic.
Public Functions
-
inline ConstantSPDMetric()
Default: identity weight matrix (only for static Dim).
The default metric is the standard ambient inner product, which is the “natural” choice for every built-in manifold (Sphere/Euclidean/Torus). For
Dim == Eigen::Dynamicthe size is unknown at compile time, so use theint nconstructor below instead.
-
inline explicit ConstantSPDMetric(int n)
Dynamic-size identity factory (size n×n).
- Parameters:
n – Dimension of the SPD matrix.
-
inline explicit ConstantSPDMetric(const Eigen::Matrix<double, Dim, Dim> &A)
Construct with a given SPD weight matrix.
- Parameters:
A – Symmetric positive-definite matrix defining the metric.
-
inline double inner(const Eigen::Vector<double, Dim>&, const Eigen::Vector<double, Dim> &u, const Eigen::Vector<double, Dim> &v) const
Compute the inner product \( \langle u, v \rangle = u^\top A \, v \).
- Parameters:
u – First tangent vector.
v – Second tangent vector.
- Returns:
The inner product value.
-
inline double norm(const Eigen::Vector<double, Dim> &p, const Eigen::Vector<double, Dim> &v) const
Compute the norm \( \|v\| = \sqrt{v^\top A \, v} \).
- Parameters:
p – Base point.
v – Tangent vector.
- Returns:
The norm value.
-
inline Eigen::MatrixXd inner_matrix(const Eigen::Vector<double, Dim>&, const Eigen::MatrixXd &U, const Eigen::MatrixXd &V) const
Batched inner product: \(U^\top A\, V\) in a single matrix multiply.
Provides the
HasBatchInnerMatrixfast path for algorithms that evaluate a tangent-metric tensor in a basis (e.g.,natural_gradient_fd). ForConstantSPDMetricthis is a simple linear-algebra shortcut; the bigger win is for point-dependent metrics likeKineticEnergyMetricwhere the expensive mass matrix is evaluated once instead of \(d^2\) times.
-
class SE2LeftInvariantMetric
Left-invariant metric on SE(2).
The inner product is constant (left-invariant): \( \langle u, v \rangle = w_x u_x v_x + w_y u_y v_y + w_\theta u_\theta v_\theta \). The weights \( (w_x, w_y, w_\theta) \) allow anisotropic cost, e.g. penalizing lateral motion for car-like robots.
Implementation: this is
ConstantSPDMetric<3>withA = diag(w_x, w_y, w_\theta). Theweights_field is preserved alongside the base metric so thatSE2::has_riemannian_log_runtime()can quickly check unit weights without inspecting the full SPD matrix.Public Functions
-
inline SE2LeftInvariantMetric()
Construct with unit weights (isotropic).
-
inline SE2LeftInvariantMetric(double wx, double wy, double wtheta)
Construct with explicit weights.
- Parameters:
wx – Translational weight in x.
wy – Translational weight in y.
wtheta – Rotational weight.
-
inline const Eigen::Vector3d &weights() const
Access the diagonal weight vector \( (w_x, w_y, w_\theta) \).
-
inline double inner(const Eigen::Vector3d &p, const Eigen::Vector3d &u, const Eigen::Vector3d &v) const
Compute the inner product via the wrapped ConstantSPDMetric.
- Parameters:
p – Base point (unused for a constant metric).
u – First tangent vector.
v – Second tangent vector.
- Returns:
The inner product value.
-
inline Eigen::MatrixXd inner_matrix(const Eigen::Vector3d &p, const Eigen::MatrixXd &U, const Eigen::MatrixXd &V) const
Batched inner product via the wrapped ConstantSPDMetric.
- Parameters:
p – Base point.
U – Matrix whose columns are tangent vectors.
V – Matrix whose columns are tangent vectors.
- Returns:
\( U^\top A \, V \).
-
inline double norm(const Eigen::Vector3d &p, const Eigen::Vector3d &v) const
Compute the norm \( \|v\| = \sqrt{\langle v, v \rangle} \).
- Parameters:
p – Base point.
v – Tangent vector.
- Returns:
The norm value.
Public Static Functions
-
static inline SE2LeftInvariantMetric car_like(const double turning_radius, const double lateral_penalty = 100.0)
Create a car-like metric with a specified effective turning radius.
The metric \( g = \mathrm{diag}(w_x, w_y, w_\theta) \) with high \( w_y \) suppresses lateral motion. The effective minimum turning radius of the resulting geodesic is approximately \( r_{\mathrm{eff}} \approx \sqrt{w_\theta / w_x} \).
Note
Soft constraint only: the metric penalizes but does not forbid motions violating the turning radius. Near start/goal the planner may produce in-place rotations.
- Parameters:
turning_radius – Desired effective turning radius.
lateral_penalty – Weight for lateral (y) motion — higher values more strongly suppress sideslip (default 100.0).
- Returns:
An SE2LeftInvariantMetric configured for car-like behavior.
-
inline SE2LeftInvariantMetric()
-
template<typename MassMatrixFn>
class KineticEnergyMetric Kinetic energy metric where the inner product is defined by a configuration-dependent mass matrix.
The inner product at configuration \( q \) is: \( \langle u, v \rangle_q = u^\top M(q) \, v \) where \( M(q) \) is a symmetric positive-definite mass matrix returned by the user-provided callable.
- Template Parameters:
MassMatrixFn – A callable type with signature
auto operator()(const Point& q) -> Eigen::MatrixXd(or fixed-size matrix).
Public Functions
-
inline explicit KineticEnergyMetric(MassMatrixFn fn)
Construct with a mass matrix function.
- Parameters:
fn – Callable returning the SPD mass matrix at a given configuration.
-
template<typename Point, typename Tangent>
inline double inner(const Point &q, const Tangent &u, const Tangent &v) const Compute the inner product \( \langle u, v \rangle_q = u^\top M(q) \, v \).
- Parameters:
q – Configuration point.
u – First tangent vector.
v – Second tangent vector.
- Returns:
The inner product value.
-
template<typename Point, typename Tangent>
inline double norm(const Point &q, const Tangent &v) const Compute the norm \( \|v\|_q = \sqrt{v^\top M(q) \, v} \).
- Parameters:
q – Configuration point.
v – Tangent vector.
- Returns:
The norm value.
-
template<typename Point>
inline Eigen::MatrixXd inner_matrix(const Point &q, const Eigen::MatrixXd &U, const Eigen::MatrixXd &V) const Batched inner product: \(U^\top M(q)\, V\) computed with a single call to the mass-matrix function.
This is the performance-critical path for
natural_gradient_fdwhen the mass matrix is expensive to compute (e.g., forward kinematics for a manipulator): instead of callingmass_matrix_fn_(q)for every scalar \(G_{ij} = \langle e_i, e_j\rangle_q\), we call it once and form the entire \(d\times d\) tensor in a single matmul.
-
inline double injectivity_radius() const
Return the injectivity radius \( \infty \) (assumes flat topology).
-
template<typename MassMatrixFn, typename PotentialFn>
class JacobiMetric Jacobi metric conformally scaling a kinetic energy metric by the available kinetic energy \( H - P(q) \).
The inner product at configuration \( q \) is: \( \langle u, v \rangle_q = 2\,(H - P(q))\, u^\top M(q) \, v \) where \( H \) is the total energy, \( P(q) \) is the potential, and \( M(q) \) is the mass matrix. Geodesics of this metric are the natural motions of the mechanical system (Maupertuis’ principle).
Implementation: this is a thin composition of
KineticEnergyMetric(the mass matrix) andWeightedMetric(the configuration-dependent scaling). Theinner,inner_matrix, andnormmethods forward to the composed metric — no duplicated mass-matrix or potential-evaluation logic.- Template Parameters:
MassMatrixFn – Callable returning the SPD mass matrix at \( q \).
PotentialFn – Callable returning the scalar potential \( P(q) \).
Public Functions
-
inline JacobiMetric(MassMatrixFn mass_fn, PotentialFn pot_fn, double H)
Construct a Jacobi metric.
- Parameters:
mass_fn – Callable returning the SPD mass matrix.
pot_fn – Callable returning the potential energy.
H – Total energy (must satisfy \( H > P(q) \) everywhere on the path).
-
template<typename Point, typename Tangent>
inline double inner(const Point &q, const Tangent &u, const Tangent &v) const Compute the inner product \( 2(H - P(q))\, u^\top M(q) \, v \).
- Parameters:
q – Configuration point.
u – First tangent vector.
v – Second tangent vector.
- Returns:
The inner product value.
-
template<typename Point, typename Tangent>
inline double norm(const Point &q, const Tangent &v) const Compute the norm \( \|v\|_q = \sqrt{2(H - P(q))\, v^\top M(q) \, v} \).
- Parameters:
q – Configuration point.
v – Tangent vector.
- Returns:
The norm value.
-
template<typename Point>
inline Eigen::MatrixXd inner_matrix(const Point &q, const Eigen::MatrixXd &U, const Eigen::MatrixXd &V) const Batched inner product: \(U^\top \bigl(2(H - P(q)) M(q)\bigr) V\) computed with a single evaluation of \(M(q)\) and \(P(q)\) through the wrapped
WeightedMetric.
-
inline double total_energy() const
Return the total energy \( H \) set at construction.
-
template<typename JacobianFn, typename TaskMetricFn>
class PullbackMetric Pullback metric that maps a task-space metric to configuration space via the Jacobian.
The inner product at configuration \( q \) is: \( \langle u, v \rangle_q = u^\top J(q)^\top G_X(q) \, J(q) \, v + \lambda \, u^\top v \) where \( J(q) \) is the task-space Jacobian, \( G_X(q) \) is the task-space metric (SPD), and \( \lambda \) is an optional regularization parameter ensuring positive-definiteness even at singularities.
- Template Parameters:
JacobianFn – Callable returning the Jacobian matrix at \( q \).
TaskMetricFn – Callable returning the task-space SPD metric at \( q \).
Public Functions
-
inline PullbackMetric(JacobianFn jac_fn, TaskMetricFn task_fn, double lambda = 0.0)
Construct a pullback metric.
- Parameters:
jac_fn – Callable returning the Jacobian.
task_fn – Callable returning the task-space metric.
lambda – Regularization (default 0).
-
template<typename Point, typename Tangent>
inline double inner(const Point &q, const Tangent &u, const Tangent &v) const Compute the inner product.
- Parameters:
q – Configuration point.
u – First tangent vector.
v – Second tangent vector.
- Returns:
The inner product value.
-
template<typename Point, typename Tangent>
inline double norm(const Point &q, const Tangent &v) const Compute the norm.
- Parameters:
q – Configuration point.
v – Tangent vector.
- Returns:
The norm value.
-
template<typename Point>
inline Eigen::MatrixXd inner_matrix(const Point &q, const Eigen::MatrixXd &U, const Eigen::MatrixXd &V) const Batched inner product: \(U^\top (J^\top G J + \lambda I)\, V\) with a single pair of Jacobian / task-metric evaluations.
-
inline double lambda() const
Access the regularization parameter.
-
template<typename MetricT, typename AlphaT = double>
class WeightedMetric Metric wrapper that scales another metric by a constant or configuration-dependent factor \(\alpha\).
The inner product is: \( \langle u, v \rangle_q = \alpha(q) \cdot \langle u, v \rangle^{\mathrm{base}}_q \)
The alpha parameter can be either:
a constant
double(e.g.WeightedMetric{base, 3.0})a callable
Fn(q) -> doublefor configuration-dependent scaling (used byJacobiMetric, region-avoiding metrics, etc.).
- Template Parameters:
MetricT – The base metric type.
AlphaT – Scaling factor type — either
doubleor a callable.
Public Functions
-
inline WeightedMetric(MetricT base, AlphaT alpha)
Construct a weighted metric.
- Parameters:
base – The base metric to scale.
alpha – Scaling factor — constant
doubleor callableFn(q) -> double.
-
template<typename Point, typename Tangent>
inline double inner(const Point &q, const Tangent &u, const Tangent &v) const Compute the scaled inner product \(\alpha(q) \langle u, v \rangle^{\mathrm{base}}_q\).
- Parameters:
q – Configuration point.
u – First tangent vector.
v – Second tangent vector.
- Returns:
The scaled inner product value.
-
template<typename Point, typename Tangent>
inline double norm(const Point &q, const Tangent &v) const Compute the scaled norm \(\|v\|_q = \sqrt{\alpha(q) \langle v, v \rangle^{\mathrm{base}}_q}\).
- Parameters:
q – Configuration point.
v – Tangent vector.
- Returns:
The scaled norm value.
-
template<typename Point>
inline Eigen::MatrixXd inner_matrix(const Point &q, const Eigen::MatrixXd &U, const Eigen::MatrixXd &V) const Batched inner product: forwards to the base metric’s
inner_matrixwhen available and scales the result by \(\alpha(q)\).
-
inline double injectivity_radius() const
Forward injectivity radius from the base metric — only valid for constant-scalar \(\alpha\) (a config-dependent alpha breaks the uniform-scaling guarantee).
-
template<typename BaseMetricT, typename SDFFn>
class SDFConformalMetric Conformal metric that scales a base metric by an obstacle proximity field.
The inner product is: \( \langle u, v \rangle_q = c(q) \cdot \langle u, v \rangle^{\mathrm{base}}_q \)
where the conformal factor is: \( c(q) = 1 + \kappa \exp(-\beta \cdot \mathrm{sdf}(q)) \)
This makes the metric expensive near obstacles (low SDF) and unmodified far away (high SDF), causing geodesics to naturally maintain clearance. With multiple obstacles, geodesics follow channels equidistant from obstacle surfaces.
The SDF callable should return a smooth signed distance field where positive values indicate free space. For circular obstacles, use log-sum-exp smooth-min to avoid gradient discontinuities at Voronoi boundaries. For grid-based distance transforms, use bilinear interpolation.
- Template Parameters:
BaseMetricT – The base metric type (e.g.,
SE2LeftInvariantMetric).SDFFn – Callable with signature
double(const Point&)returning the signed distance to the nearest obstacle surface.
Public Functions
-
inline SDFConformalMetric(BaseMetricT base, SDFFn sdf, double kappa = 5.0, double beta = 3.0)
Construct an SDF-based conformal metric.
- Parameters:
base – The base metric to scale.
sdf – Callable returning signed distance (positive = free space).
kappa – Strength of obstacle repulsion (higher = more clearance).
beta – Falloff rate (higher = tighter to obstacle surfaces).
-
template<typename Point, typename Tangent>
inline double inner(const Point &q, const Tangent &u, const Tangent &v) const Compute the scaled inner product \( c(q) \langle u, v \rangle^{\mathrm{base}}_q \).
-
template<typename Point, typename Tangent>
inline double norm(const Point &q, const Tangent &v) const Compute the scaled norm \( \|v\|_q = \sqrt{c(q)} \|v\|^{\mathrm{base}}_q \).
-
template<typename Point>
inline Eigen::MatrixXd inner_matrix(const Point &q, const Eigen::MatrixXd &U, const Eigen::MatrixXd &V) const Batched inner product scaled by the conformal factor.
-
inline const BaseMetricT &base() const
Access the base metric.
-
inline double kappa() const
Get the strength parameter.
-
inline double beta() const
Get the falloff rate parameter.
Collision
-
class DistanceGrid
A 2D precomputed distance transform with bilinear interpolation.
Stores obstacle distances at regular grid points. Queried in world coordinates (meters); returns interpolated distance to nearest obstacle. Positive = free space, zero/negative = obstacle.
Public Functions
-
inline DistanceGrid(const int width, const int height, const double resolution, std::vector<double> data)
Construct from raw data.
- Parameters:
width – Grid width in cells.
height – Grid height in cells.
resolution – Meters per cell.
data – Row-major distance values: data[r * width + c].
-
inline bool load(const std::string &filename)
Load from the geodex distance transform file format.
Format:
width height resolutionon the first line, followed byheight * widthdouble values in row-major order.
-
inline double distance_at(const double x_m, const double y_m) const
Query distance at world coordinates using bilinear interpolation.
-
inline void distance_at_batch(const double *x, const double *y, double *out, const int n) const
Batch query: evaluate distance at N world-coordinate points.
On ARM NEON and x86 SSE2, processes 2 points per iteration with vectorized bilinear interpolation math. Grid value gathering remains scalar on both architectures.
-
inline int width() const
Grid width in cells.
-
inline int height() const
Grid height in cells.
-
inline double resolution() const
Cell size in meters.
-
inline const std::vector<double> &data() const
Raw distance data array.
-
inline DistanceGrid(const int width, const int height, const double resolution, std::vector<double> data)
-
class GridSDF
SDF callable wrapping a DistanceGrid for use with SDFConformalMetric.
Extracts (x, y) from the configuration point and queries the grid.
Public Functions
-
inline explicit GridSDF(const DistanceGrid *grid)
Construct from a DistanceGrid pointer.
-
inline explicit GridSDF(const DistanceGrid *grid)
-
template<typename SDFType>
class InflatedSDF Wraps any SDF and subtracts a constant inflation radius.
Equivalent to Minkowski expansion of all obstacles by
inflation. Useful for point-robot queries that need to account for robot radius.
-
class PolygonFootprint
A convex polygon footprint represented as body-frame perimeter samples.
Samples are stored in SoA layout (separate x[] and y[] arrays) padded to an even count for NEON 2-wide processing. The transform() method rotates and translates all samples to world frame using a single sincos call and NEON vectorized rotation.
Note
Only convex polygons are supported. For non-convex shapes, interior sampling would be needed (future work).
Public Functions
-
inline PolygonFootprint(const std::vector<Eigen::Vector2d> &vertices, const int samples_per_edge)
Construct from polygon vertices with a specified number of samples per edge.
Vertices define a convex polygon in the body frame, centered at the origin. Samples are placed uniformly along each edge, including the start vertex but excluding the end vertex (to avoid duplicates at corners).
-
inline int sample_count() const
Total number of perimeter samples (padded to even for NEON).
-
inline int sample_count_raw() const
Actual (unpadded) number of perimeter samples.
-
inline const double *body_x() const
Body-frame x-coordinates (SoA, padded).
-
inline const double *body_y() const
Body-frame y-coordinates (SoA, padded).
-
inline double bounding_radius() const
Bounding radius from origin (for early-out tests).
-
inline void transform(const double x, const double y, const double theta, double *wx, double *wy) const
Transform body-frame samples to world frame at pose (x, y, theta).
SIMD strategy:
One sincos(theta) call shared across all samples
NEON 2-wide: rotate + translate 2 points per iteration
For a rectangle with samples_per_edge=4: 16 samples → 8 iterations
- Parameters:
x – World x-coordinate of the polygon center.
y – World y-coordinate of the polygon center.
theta – Rotation angle (radians).
wx – [out] World-frame x-coordinates (must have capacity >= sample_count()).
wy – [out] World-frame y-coordinates (must have capacity >= sample_count()).
Public Static Functions
-
static inline PolygonFootprint rectangle(const double half_length, const double half_width, const int samples_per_edge)
Convenience factory for a rectangular footprint.
- Parameters:
half_length – Half-extent along the local x-axis.
half_width – Half-extent along the local y-axis.
samples_per_edge – Number of sample points per edge.
-
inline PolygonFootprint(const std::vector<Eigen::Vector2d> &vertices, const int samples_per_edge)
-
class FootprintGridChecker
Polygon-vs-grid collision checker with SIMD acceleration.
Precomputes a polygon footprint as body-frame perimeter samples. At query time, transforms all samples to world frame and batch-queries the distance grid. Returns either a binary collision result or a continuous signed distance field (minimum grid distance across all samples minus safety margin).
Thread-safe: uses thread_local scratch buffers for OMPL’s parallel motion validation.
Public Functions
-
inline FootprintGridChecker(const DistanceGrid *grid, PolygonFootprint footprint, const double safety_margin = 0.0)
Construct a footprint checker.
- Parameters:
grid – Pointer to the distance grid (must outlive this object).
footprint – Polygon footprint with precomputed body-frame samples.
safety_margin – Extra clearance subtracted from distances (default 0).
-
inline bool is_valid(const Eigen::Vector3d &q) const
Binary collision test. Returns true if the footprint is collision-free.
-
template<typename Point>
inline double operator()(const Point &q) const SDF: minimum grid distance across all perimeter samples minus safety margin.
Positive = clear, negative = collision. Suitable for use with SDFConformalMetric to bias planning away from obstacles.
-
inline const DistanceGrid *grid() const
Get the underlying distance grid.
-
inline const PolygonFootprint &footprint() const
Get the polygon footprint.
-
inline double safety_margin() const
Get the safety margin.
-
inline FootprintGridChecker(const DistanceGrid *grid, PolygonFootprint footprint, const double safety_margin = 0.0)
-
class CircleSDF
Signed distance to a single circular obstacle.
Returns positive values in free space and negative inside the circle: \( \mathrm{sdf}(q) = \|q_{xy} - c\| - r \)
Public Functions
-
template<typename Point>
inline double operator()(const Point &q) const Evaluate signed distance from point to circle boundary.
-
inline double cx() const
X-coordinate of the circle center.
-
inline double cy() const
Y-coordinate of the circle center.
-
inline double radius() const
Radius of the circle.
-
inline double radius_sq() const
Squared radius of the circle.
-
template<typename Point>
-
class CircleSmoothSDF
Log-sum-exp smooth-min SDF over a collection of circular obstacles.
Produces a smooth approximation to the minimum signed distance across all circles. The smoothing parameter
betacontrols how closely the smooth-min approximates the hard minimum (higher values give a tighter approximation but sharper gradient transitions).The numerically stable computation is:
\[ \mathrm{sdf}(q) = -\frac{1}{\beta}\left(m + \ln\sum_i \exp(-\beta\,d_i - m)\right), \quad m = \max_i(-\beta\,d_i) \]Public Functions
-
inline CircleSmoothSDF(std::vector<CircleSDF> circles, const double beta = 20.0)
Construct from a list of circles and smoothing parameter.
-
template<typename Point>
inline double operator()(const Point &q) const Evaluate smooth signed distance at point (x, y).
-
template<typename Point>
inline bool is_free(const Point &q) const Check if a point is outside all circles (binary collision test).
-
inline double beta() const
Get the log-sum-exp smoothing parameter.
-
inline CircleSmoothSDF(std::vector<CircleSDF> circles, const double beta = 20.0)
-
struct RectObstacle
An oriented rectangle obstacle defined by center, rotation, and half-extents.
-
class RectSmoothSDF
Fused SDF + log-sum-exp for oriented rectangles with SIMD acceleration.
SIMD strategy (ARM NEON, 2-wide float64):
SoA layout: cache-line-friendly, NEON-loadable
2-wide processing: 2 obstacles per iteration, branchless via vbslq
Bounding sphere early-out: skip obstacles where center distance exceeds diagonal + skip_dist (where exp(-beta*d) ~ 0)
Inflation applied inside the SIMD loop (no separate wrapper needed)
fast_exp_neon for the log-sum-exp accumulation
Scalar fallback provided for platforms without SIMD. x86 SSE2 path uses 2-wide float64 processing with optional SSE4.1/FMA.
Public Functions
-
inline RectSmoothSDF(std::vector<RectObstacle> obstacles, const double beta = 20.0, const double inflation = 0.0)
Construct from obstacles with smoothing and optional inflation.
-
template<typename Point>
inline double operator()(const Point &q) const Evaluate smooth signed distance at point (x, y).
-
inline const std::vector<RectObstacle> &obstacles() const
Get the rectangle obstacles.
-
inline double beta() const
Get the log-sum-exp smoothing parameter.
-
inline double inflation() const
Get the inflation radius.
-
inline bool geodex::collision::rects_overlap(const RectObstacle &a, const RectObstacle &b)
Separating Axis Theorem (SAT) overlap test for two oriented rectangles.
- Returns:
true if the rectangles overlap (collide).
Sampling
-
class StochasticSampler
Pseudo-random sampler wrapping
std::mt19937.Default construction uses a shared
thread_localMersenne-Twister generator, preserving the pre-refactor per-manifold random_point() semantics and zero-cost instantiation. Passing an explicit seed creates an owned generator with a reproducible sequence — useful for tests and benchmarks.Public Functions
-
StochasticSampler() = default
Default: share a thread-local generator.
-
inline explicit StochasticSampler(std::uint64_t seed)
Seeded: own a generator for reproducible sequences.
-
inline void seed(std::uint64_t s)
Reseed the sampler; transitions to an owned generator.
-
inline void sample_box(const int d, Eigen::Ref<Eigen::VectorXd> out)
Fill
out[0..d-1]with uniform values in \([0, 1)\).
-
StochasticSampler() = default
-
class HaltonSampler
Halton low-discrepancy sampler (deterministic quasi-random).
Produces a fully reproducible quasi-random sequence by advancing an internal 1-based index. Coordinates are computed per dimension via
detail::van_der_corputwith the firstdprimes. Maximum supported dimension isdetail::halton_primes.size()(30).Public Functions
-
HaltonSampler() = default
Default: start the sequence at index 1.
-
inline explicit HaltonSampler(std::uint64_t start_index)
Start the sequence at an explicit index.
-
inline void seed(std::uint64_t s)
Reset the sequence index.
-
inline void sample_box(const int d, Eigen::Ref<Eigen::VectorXd> out)
Fill
out[0..d-1]with the next Halton sample.
-
HaltonSampler() = default
-
template<typename S>
concept Sampler - #include <sampler.hpp>
Concept: a type that fills a length-
dvector with uniform samples in \([0, 1)\).
-
template<typename S>
concept SeedableSampler - #include <sampler.hpp>
Concept: a
Samplerthat also supports explicit reseeding.
Heuristics
Algorithms
Warning
doxygenfunction: Unable to resolve function “geodex::distance_midpoint” with arguments None in doxygen xml output for project “geodex” from directory: ../build/docs/doxygen/xml. Potential matches:
- template<RiemannianManifold M> auto distance_midpoint(const M &m, const typename M::Point &a, const typename M::Point &b) -> typename M::Scalar
- template<typename BaseM, typename MetricT> auto distance_midpoint(const ConfigurationSpace<BaseM, MetricT> &m, const Eigen::Vector3d &a, const Eigen::Vector3d &b) -> double
- template<typename MetricT, typename RetractionT, typename SamplerT> auto distance_midpoint(const SE2<MetricT, RetractionT, SamplerT> &m, const Eigen::Vector3d &a, const Eigen::Vector3d &b) -> double
-
struct InterpolationSettings
Settings for the discrete geodesic walk.
Each iteration takes a Riemannian step of length \(\min(\texttt{step\_size}, \text{remaining distance})\) in the descent direction. Iteration count and returned-path size therefore scale as approximately \(\text{initial\_distance} / \texttt{step\_size}\), so
step_sizealso functions as the effective path resolution (the maximum Riemannian distance between consecutive returned points).Fast path: the algorithm first tries the Riemannian logarithm as the descent direction, exploiting the identity \(\nabla_g(\tfrac{1}{2}\, d_g^2(\cdot, q))(x) = -\log_x^g(q)\) which holds on any Riemannian manifold when
xis strictly insideq’s injectivity radius andlogis the Riemannian logarithm of the metric in use. A progress check on each step verifies that the proposed point actually decreased the distance to target. When the check fails (e.g., the retraction is not the true exponential map, or the metric differs from the one implied by the retraction), the algorithm falls back for that step only to a central finite-difference natural gradient computed from the manifold’sinnerproduct.Public Members
-
double step_size = 0.5
Max Riemannian step per iteration; also the effective path resolution.
-
double convergence_tol = 1e-4
Absolute stop threshold on \(|\log(\text{current}, \text{target})|_R\).
-
double convergence_rel = 1e-3
Relative stop threshold: also stop when distance drops below
convergence_rel * initial_distance.
-
int max_steps = 100
Maximum number of successful gradient-descent steps.
-
double fd_epsilon = 0.0
Central finite-difference step for the fallback gradient.
Set to 0 to auto-select as
max(1e-8, 1e-5 * max(1, initial_distance)).
-
double distortion_ratio = 1.5
Max ratio \(|\log(\text{current}, \text{proposed})|_R / \text{step\_used}\) before the retraction is considered to have over-shot.
If violated, the step cap is halved and the iteration retries. This guards against retractions that blow up under curvature and is usually 1.5 (modest slack over a perfect isometry).
-
double growth_factor = 1.5
Factor by which the current step cap grows back toward
step_sizeafter each successful iteration.Set to 1.0 to disable growth.
-
double min_step_size = 1e-12
Floor below which the step cap triggers a
StepShrunkToZerofailure.
-
double gradient_eps = 1e-12
Riemannian-norm threshold below which the gradient is considered vanished (triggers
GradientVanished).
-
double cut_locus_eps = 1e-10
\(|\log|_R\) threshold that, combined with a nonzero ambient gap, flags a cut-locus situation (e.g., antipodal points on the sphere where
logreturns zero).
-
bool force_log_direction = false
Force the log-based direction even when
is_riemannian_log()is false.When true, the algorithm always uses
log(current, target)as the descent direction and never falls back to the FD natural gradient. The metric’s norm and distance still control step sizing and convergence. This produces smoother paths (no FD oscillation) but the path follows the base retraction’s geodesic rather than the true Riemannian geodesic of the configured metric.
-
double fd_midpoint_guard_tau = 0.25
Relative-error threshold above which the midpoint distance surrogate used by the FD gradient is deemed unreliable and falls back to
|log(a,b)|_R.natural_gradient_fdsamples \(d^2(p \pm h\,e_i, q)\) via a third-order-accurate midpoint formula (seedistance_midpoint). For a true Riemannian midpoint we have \(\log_m(a) = -\log_m(b)\), so the quantity \(\|v_{ma} + v_{mb}\|_m / \|v_{mb} - v_{ma}\|_m\) is zero. When this ratio exceedstau, the midpoint is considered unreliable (non-Riemannian retraction, cut locus, or non-smoothness between the samples) and the FD sample falls back to|log|_Rfor the entire basis direction. The count of fallbacks is reported onInterpolationResult::fd_midpoint_fallbacks. Set to 0.0 to force via-log for every sample. Default 0.25.
-
double step_size = 0.5
-
enum class geodex::InterpolationStatus
Termination status for the discrete geodesic walk.
Values:
-
enumerator Converged
Distance to target fell below convergence tolerance.
-
enumerator MaxStepsReached
Iteration budget exhausted without reaching tolerance.
-
enumerator GradientVanished
Riemannian gradient norm is ~0 at a non-target point.
-
enumerator CutLocus
logcollapsed to ~0 while start and target are distinct (e.g.antipodal on a sphere).
-
enumerator StepShrunkToZero
Distortion halving drove step size below
min_step_size.
-
enumerator DegenerateInput
start == targeton entry; returned a single-point path immediately.
-
enumerator Converged
-
template<typename PointT>
struct InterpolationResult Output of the discrete geodesic interpolation.
- Template Parameters:
PointT – Point type of the manifold (e.g.
Eigen::Vector3d).
Public Members
-
InterpolationStatus status = InterpolationStatus::Converged
Termination reason — always check this before using the path for downstream work.
-
int iterations = 0
Number of successful gradient steps taken (distortion retries do not count).
-
int distortion_halvings = 0
Number of times the step cap was halved due to distortion / progress failure.
-
int fd_midpoint_fallbacks = 0
Number of FD basis directions whose midpoint distance surrogate was rejected by the runtime guard and replaced with
|log|_Rfor that sample.Summed across all iterations of the walk. A nonzero value is a strong signal that the manifold/retraction/metric combination is producing a midpoint that is not the Riemannian midpoint (e.g. projection retraction on an anisotropic metric, SE(2) Euler retraction for large Δθ, cut-locus crossings, or a non-smooth metric feature within ~h of the midpoint).
-
double initial_distance = 0.0
Riemannian distance from
starttotargetat entry.
-
double final_distance = 0.0
Riemannian distance from the final iterate to
targetat exit.
-
template<RiemannianManifold M>
struct InterpolationCache Reusable scratch buffers for
discrete_geodesic.Passing a cache to
discrete_geodesiceliminates per-iteration heap allocations (for fixed-size manifolds) and per-call allocation beyond the first call (for dynamic-size manifolds). Intended for use in hot loops such as steering functions in sampling-based planners:geodex::InterpolationCache<Sphere<>> cache; for (auto& edge : edges) { auto r = geodex::discrete_geodesic(sphere, edge.a, edge.b, settings, &cache); ... }
Users who do not need this optimization can omit the cache argument and a stack-local one will be used automatically.
Public Types
Public Functions
-
inline void reset(int ambient, int d)
Resize all buffers for the given ambient and intrinsic dimensions.
- Parameters:
ambient – Ambient-space dimension of a tangent vector (typically
Tangent::size()).d – Intrinsic manifold dimension (
manifold.dim()).
Public Members
-
Eigen::Matrix<double, N, Eigen::Dynamic, 0, MaxN, MaxN> basis_mat
Basis matrix (FD path): columns are tangent basis vectors at the current point.
-
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, 0, MaxN, MaxN> G
Metric tensor \(G_{ij} = \langle e_i, e_j\rangle_p\) in the current basis.
-
Eigen::Matrix<double, Eigen::Dynamic, 1, 0, MaxN, 1> grad
Coordinate-space gradient of \(\tfrac{1}{2}\, d^2(\cdot, \text{target})\).
-
Eigen::Matrix<double, Eigen::Dynamic, 1, 0, MaxN, 1> alpha
Natural-gradient coefficients \(\alpha = -G^{-1} g\).
-
inline void reset(int ambient, int d)
-
template<RiemannianManifold M>
auto geodex::discrete_geodesic(const M &manifold, const typename M::Point &start, const typename M::Point &target, InterpolationSettings settings = {}, InterpolationCache<M> *cache = nullptr) -> InterpolationResult<typename M::Point> Walk from
starttowardtargetvia Riemannian natural gradient descent.The algorithm iteratively descends on \(\varphi(x) = \tfrac{1}{2}\, d^2(x, \text{target})\) with step length capped by
settings.step_sizeper iteration. Each iteration tries the Riemannian logarithm direction first (exploiting \(\nabla\varphi = -\log_x(\text{target})\) on any Riemannian manifold away from the cut locus) and verifies via a progress check. When the log direction does not produce enough distance decrease (e.g., because the retraction is a projection, or the metric is custom), the algorithm falls back for that step to a central finite-difference natural gradient computed from the manifold’sinnerproduct.The returned
InterpolationResultcarries the path, a termination status enum, iteration count, and the initial/final distances — allowing callers to distinguish successful convergence fromMaxStepsReached,CutLocus,GradientVanished,StepShrunkToZero, andDegenerateInput.Walk semantics: iteration count and path size both scale as \(\approx \text{initial\_distance} / \texttt{step\_size}\). Reduce
step_sizefor higher path resolution.Note
See Kyaw, P. T., & Kelly, J. (2026). Geometry-Aware Sampling-Based Motion Planning on Riemannian Manifolds. arXiv:2602.00992. The identity \(\nabla_g(\tfrac{1}{2}\, d_g^2(\cdot, q))(x) = -\log_x^g(q)\) is standard; see Sakai, Riemannian Geometry, §IV.5 and do Carmo, Riemannian Geometry, Ch 13 Prop 3.6.
- Template Parameters:
M – A type satisfying
RiemannianManifold.- Parameters:
manifold – The manifold instance.
start – Starting point.
target – Target point to walk toward.
settings – Algorithm parameters.
cache – Optional reusable cache. If null, a stack-local one is used.
- Returns:
An
InterpolationResultcarrying the path and termination diagnostics.
-
template<typename M>
concept HasBatchInnerMatrix - #include <metric.hpp>
A manifold that exposes a batched inner-product, computing \(U^\top M(p) V\) in one call.
This is an optional optimization hook for point-dependent metrics where the expensive part is evaluating the metric tensor \(M(p)\) (e.g., forward kinematics for a kinetic-energy metric). Providing
inner_matrixallows algorithms that compute a \(d \times d\) metric tensor in a tangent basis (natural_gradient_fdis the canonical consumer) to evaluate \(M(p)\) once instead of \(d^2\) times.Algorithms that only need pointwise evaluation use the scalar
innerpath and do not require metrics to provideinner_matrix.
OMPL Integration
-
template<typename ManifoldT>
class GeodexStateSpace : public ompl::base::StateSpace OMPL state space adapter for geodex Riemannian manifolds.
Wraps a geodex
RiemannianManifoldas anompl::base::StateSpace, delegating distance, interpolation, and sampling to the manifold’s operations. States store ambient-space coordinates as rawdouble*arrays.- Template Parameters:
ManifoldT – A type satisfying
geodex::RiemannianManifold.
Public Types
-
using StateType = GeodexState<ManifoldT>
OMPL state type.
Public Functions
-
inline GeodexStateSpace(ManifoldT manifold, ob::RealVectorBounds bounds)
Construct a state space from a manifold and bounds.
- Parameters:
manifold – The geodex manifold instance.
bounds – Axis-aligned bounds for the ambient coordinates.
-
inline const ob::RealVectorBounds &getBounds() const
Access the coordinate bounds.
-
inline void setCollisionResolution(double resolution)
Set the minimum collision checking resolution in coordinate distance.
When set to a positive value,
validSegmentCount()ensures at leastceil(coord_distance / resolution)checks along each edge, independent of OMPL’slongestValidSegmentFraction. This prevents thin walls from being missed whengetMaximumExtent()is large.- Parameters:
resolution – Minimum distance (meters) between collision checks. Use 0.0 to disable (OMPL default only).
-
inline double getCollisionResolution() const
Get the collision checking resolution.
-
inline void setInterpolationMode(const InterpolationMode mode)
Set the interpolation strategy.
- Parameters:
mode – The desired interpolation mode.
-
inline InterpolationMode getInterpolationMode() const
Get the current interpolation mode.
-
inline void setInterpolationSettings(const InterpolationSettings &settings)
Set the interpolation settings for discrete geodesic computation.
- Parameters:
settings – The settings (step_size, convergence_tol, max_steps, etc.).
-
inline const InterpolationSettings &getInterpolationSettings() const
Get the current interpolation settings.
-
inline void setGeodesicStepSize(const double step_size)
Convenience: set the step size for discrete geodesic interpolation.
Controls the maximum Riemannian distance between consecutive waypoints in the cached geodesic path. Smaller values increase resolution (and computation cost). Default is 0.5.
- Parameters:
step_size – Maximum step size per iteration.
-
inline unsigned int getDimension() const override
Return the ambient dimension of the state space.
-
inline double getMaximumExtent() const override
Return the maximum extent of the state space.
- Todo:
Validate this fix properly. Current approach (max of coordinate diagonal and Riemannian corner-to-corner distance) fixes the connect-loop hang with anisotropic metrics, but the corner-to-corner Riemannian distance may not be the true maximum extent (angle wrapping, non-diagonal pairs, configuration-dependent metrics). Needs formal analysis and tests across different manifold types.
-
inline double getMeasure() const override
Return the volume of the bounding box.
-
inline void enforceBounds(ob::State *state) const override
Clamp state coordinates to the bounds.
-
inline bool satisfiesBounds(const ob::State *state) const override
Check whether all coordinates satisfy the bounds.
-
inline void copyState(ob::State *destination, const ob::State *source) const override
Copy state coordinates.
-
inline double distance(const ob::State *state1, const ob::State *state2) const override
Compute the geodesic distance between two states.
-
inline bool equalStates(const ob::State *state1, const ob::State *state2) const override
Check whether two states are equal (within tolerance).
-
inline void interpolate(const ob::State *from, const ob::State *to, double t, ob::State *state) const override
Geodesic interpolation between two states.
For manifolds where
is_riemannian_log()returns true (identity metric with matching retraction), uses the directgeodesic(p, q, t)— zero overhead. For non-flat metrics, computes a discrete geodesic via Riemannian natural gradient descent, caches the path, and serves subsequent lookups via arc-length parameterization. The cache is keyed on the (from, to) state pair; sequential calls with the same pair (as inDiscreteMotionValidator::checkMotion) amortize the computation.- Parameters:
from – Start state.
to – End state.
t – Interpolation parameter in [0, 1].
state – Output state.
-
inline ob::StateSamplerPtr allocDefaultStateSampler() const override
Allocate the default state sampler.
-
inline ob::State *allocState() const override
Allocate a new state.
-
inline void freeState(ob::State *state) const override
Free a state.
-
inline double *getValueAddressAtIndex(ob::State *state, unsigned int index) const override
Get a pointer to the coordinate at the given index.
-
inline void copyToReals(std::vector<double> &reals, const ob::State *source) const override
Copy state coordinates to a vector of doubles.
-
inline void copyFromReals(ob::State *destination, const std::vector<double> &reals) const override
Set state coordinates from a vector of doubles.
-
inline const GeodesicPathCache<ManifoldT> &getGeodesicCache() const
Read-only access to the internal cached discrete-geodesic path.
Exposed so
GeodexOptimizationObjectivecan compute the integrated arc cost for the lastinterpolate()pair without recomputing. The cache holds at most one (s1, s2) pair at a time; callers must checkmatches()before using it.
-
inline void ensureGeodesicCached(const Point &from, const Point &to) const
Populate the cache for the given endpoint pair (or no-op on hit).
Used by the optimization objective when it needs the arc cost for a pair that is not yet cached. Uses the state space’s configured
InterpolationSettings.
-
inline unsigned int validSegmentCount(const ob::State *s1, const ob::State *s2) const override
Number of collision checks for a motion between two states.
Returns the maximum of OMPL’s default segment count and a coordinate-distance-based count derived from
collision_resolution_.
-
template<typename ManifoldT>
class GeodexState : public ompl::base::State State type for GeodexStateSpace, storing ambient-space coordinates.
Wraps a raw
double*array with Eigen map accessors for convenient conversion between OMPL states and geodex manifold points.- Template Parameters:
ManifoldT – The geodex manifold type.
Public Functions
-
inline auto asEigen() const
Read-only Eigen map of the state coordinates.
-
inline auto asEigen()
Mutable Eigen map of the state coordinates.
Public Members
-
double *values = nullptr
Raw coordinate array (owned by the state space).
-
template<typename ManifoldT>
class GeodexStateSampler : public ompl::base::StateSampler State sampler for GeodexStateSpace.
Provides uniform, near-uniform, and Gaussian sampling on the manifold by sampling tangent vectors and applying the exponential map.
- Template Parameters:
ManifoldT – The geodex manifold type.
Public Functions
-
inline explicit GeodexStateSampler(const ob::StateSpace *space)
Construct a sampler for the given state space.
- Parameters:
space – The GeodexStateSpace to sample from.
-
inline void sampleUniform(ob::State *state) override
Sample a state uniformly within the bounds.
-
inline void sampleUniformNear(ob::State *state, const ob::State *near, double distance) override
Sample a state uniformly near another state at a given distance.
- Parameters:
state – Output state.
near – Reference state to sample around.
distance – Desired geodesic distance from
near.
-
inline void sampleGaussian(ob::State *state, const ob::State *mean, double stdDev) override
Sample a state from a Gaussian distribution centered at
mean.- Parameters:
state – Output state.
mean – Center of the Gaussian.
stdDev – Standard deviation in the tangent space.