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 {}