Skip to main content

cartan_core/
error.rs

1// ~/cartan/cartan-core/src/error.rs
2
3//! Error types for cartan operations.
4//!
5//! CartanError covers all failure modes in Riemannian geometry computations:
6//! logarithmic map failures at cut loci, numerical breakdowns in matrix
7//! decompositions, constraint violations, and optimizer convergence failures.
8
9use core::fmt;
10
11use crate::Real;
12
13/// The unified error type for all cartan operations.
14///
15/// Each variant captures a specific class of failure with enough context
16/// to diagnose the problem. Mathematical operations that can fail (log map,
17/// parallel transport across cut locus, Cholesky of near-singular matrix)
18/// return Result<T, CartanError>.
19///
20/// Under `no_alloc`, message fields are `&'static str` (no heap).
21/// Under `alloc` or `std`, message fields are `String` (rich formatting).
22#[derive(Debug, Clone)]
23pub enum CartanError {
24    /// Log map failed: point is on or near the cut locus.
25    ///
26    /// On the sphere, this means the two points are nearly antipodal.
27    /// On SO(n), this means the rotation angle is near pi.
28    /// On Cartan-Hadamard manifolds (SPD, Hyperbolic), this should
29    /// never occur since the cut locus is empty.
30    CutLocus {
31        #[cfg(feature = "alloc")]
32        message: alloc::string::String,
33        #[cfg(not(feature = "alloc"))]
34        message: &'static str,
35    },
36
37    /// A matrix decomposition or numerical computation failed.
38    ///
39    /// Examples: Cholesky on a matrix that lost positive-definiteness
40    /// due to roundoff, SVD that did not converge, matrix logarithm
41    /// of a matrix with negative eigenvalues.
42    NumericalFailure {
43        #[cfg(feature = "alloc")]
44        operation: alloc::string::String,
45        #[cfg(feature = "alloc")]
46        message: alloc::string::String,
47        #[cfg(not(feature = "alloc"))]
48        operation: &'static str,
49        #[cfg(not(feature = "alloc"))]
50        message: &'static str,
51    },
52
53    /// Point does not satisfy the manifold constraint.
54    ///
55    /// The `constraint` field describes what was checked (e.g., "||p|| = 1"
56    /// for the sphere), and `violation` gives the magnitude of the deviation.
57    NotOnManifold {
58        #[cfg(feature = "alloc")]
59        constraint: alloc::string::String,
60        #[cfg(not(feature = "alloc"))]
61        constraint: &'static str,
62        violation: Real,
63    },
64
65    /// Tangent vector is not in the tangent space at the given point.
66    ///
67    /// The `constraint` field describes the tangent space condition
68    /// (e.g., "p^T v = 0" for the sphere).
69    NotInTangentSpace {
70        #[cfg(feature = "alloc")]
71        constraint: alloc::string::String,
72        #[cfg(not(feature = "alloc"))]
73        constraint: &'static str,
74        violation: Real,
75    },
76
77    /// Line search failed to find a step size satisfying the Armijo condition.
78    LineSearchFailed { steps_tried: usize },
79
80    /// Optimizer did not converge within the maximum number of iterations.
81    ConvergenceFailure {
82        iterations: usize,
83        gradient_norm: Real,
84    },
85}
86
87impl fmt::Display for CartanError {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        match self {
90            CartanError::CutLocus { message } => {
91                write!(f, "cut locus: {}", message)
92            }
93            CartanError::NumericalFailure { operation, message } => {
94                write!(f, "numerical failure in {}: {}", operation, message)
95            }
96            CartanError::NotOnManifold {
97                constraint,
98                violation,
99            } => {
100                write!(
101                    f,
102                    "point not on manifold: {} violated by {}",
103                    constraint, violation
104                )
105            }
106            CartanError::NotInTangentSpace {
107                constraint,
108                violation,
109            } => {
110                write!(
111                    f,
112                    "tangent vector not in tangent space: {} violated by {}",
113                    constraint, violation
114                )
115            }
116            CartanError::LineSearchFailed { steps_tried } => {
117                write!(f, "line search failed after {} steps", steps_tried)
118            }
119            CartanError::ConvergenceFailure {
120                iterations,
121                gradient_norm,
122            } => {
123                write!(
124                    f,
125                    "optimizer did not converge after {} iterations (gradient norm: {:.2e})",
126                    iterations, gradient_norm
127                )
128            }
129        }
130    }
131}
132
133#[cfg(feature = "std")]
134impl std::error::Error for CartanError {}