amari_functional/
error.rs

1//! Error types for functional analysis operations.
2//!
3//! This module provides comprehensive error handling for functional analysis
4//! operations including space construction, operator application, and spectral
5//! decomposition.
6
7use thiserror::Error;
8
9/// Result type for functional analysis operations.
10pub type Result<T> = core::result::Result<T, FunctionalError>;
11
12/// Errors that can occur during functional analysis operations.
13#[derive(Error, Debug, Clone, PartialEq)]
14pub enum FunctionalError {
15    /// Dimension mismatch between spaces or operators.
16    #[error("Dimension mismatch: expected {expected}, got {actual}")]
17    DimensionMismatch {
18        /// Expected dimension.
19        expected: usize,
20        /// Actual dimension encountered.
21        actual: usize,
22    },
23
24    /// The space does not satisfy required completeness properties.
25    #[error("Space is not complete: {reason}")]
26    NotComplete {
27        /// Description of why completeness fails.
28        reason: String,
29    },
30
31    /// The operator is not bounded.
32    #[error("Operator is not bounded: {description}")]
33    NotBounded {
34        /// Description of the unboundedness.
35        description: String,
36    },
37
38    /// The operator is not compact.
39    #[error("Operator is not compact: {reason}")]
40    NotCompact {
41        /// Reason for non-compactness.
42        reason: String,
43    },
44
45    /// The operator does not have a valid inverse.
46    #[error("Operator is not invertible: {reason}")]
47    NotInvertible {
48        /// Reason for non-invertibility.
49        reason: String,
50    },
51
52    /// Eigenvalue computation failed.
53    #[error("Eigenvalue computation failed: {reason}")]
54    EigenvalueError {
55        /// Description of the failure.
56        reason: String,
57    },
58
59    /// Spectral decomposition failed.
60    #[error("Spectral decomposition failed: {reason}")]
61    SpectralDecompositionError {
62        /// Description of the failure.
63        reason: String,
64    },
65
66    /// The Fredholm index is undefined.
67    #[error("Fredholm index undefined: {reason}")]
68    FredholmIndexUndefined {
69        /// Reason why the index is undefined.
70        reason: String,
71    },
72
73    /// Sobolev space construction failed.
74    #[error("Sobolev space error: {description}")]
75    SobolevError {
76        /// Description of the Sobolev space error.
77        description: String,
78    },
79
80    /// Norm computation failed or is undefined.
81    #[error("Norm error: {description}")]
82    NormError {
83        /// Description of the norm error.
84        description: String,
85    },
86
87    /// Inner product computation failed.
88    #[error("Inner product error: {description}")]
89    InnerProductError {
90        /// Description of the inner product error.
91        description: String,
92    },
93
94    /// Convergence conditions not satisfied.
95    #[error("Convergence failed after {iterations} iterations: {reason}")]
96    ConvergenceError {
97        /// Number of iterations attempted.
98        iterations: usize,
99        /// Reason for convergence failure.
100        reason: String,
101    },
102
103    /// Numerical instability detected.
104    #[error("Numerical instability in {operation}: {details}")]
105    NumericalInstability {
106        /// The operation that became unstable.
107        operation: String,
108        /// Details about the instability.
109        details: String,
110    },
111
112    /// Invalid parameters provided.
113    #[error("Invalid parameters: {description}")]
114    InvalidParameters {
115        /// Description of the invalid parameters.
116        description: String,
117    },
118
119    /// Error from amari-measure.
120    #[error(transparent)]
121    MeasureError(#[from] amari_measure::MeasureError),
122
123    /// Error from amari-calculus.
124    #[error(transparent)]
125    CalculusError(#[from] amari_calculus::CalculusError),
126}
127
128impl FunctionalError {
129    /// Create a dimension mismatch error.
130    pub fn dimension_mismatch(expected: usize, actual: usize) -> Self {
131        Self::DimensionMismatch { expected, actual }
132    }
133
134    /// Create a not complete error.
135    pub fn not_complete(reason: impl Into<String>) -> Self {
136        Self::NotComplete {
137            reason: reason.into(),
138        }
139    }
140
141    /// Create a not bounded error.
142    pub fn not_bounded(description: impl Into<String>) -> Self {
143        Self::NotBounded {
144            description: description.into(),
145        }
146    }
147
148    /// Create a not compact error.
149    pub fn not_compact(reason: impl Into<String>) -> Self {
150        Self::NotCompact {
151            reason: reason.into(),
152        }
153    }
154
155    /// Create a not invertible error.
156    pub fn not_invertible(reason: impl Into<String>) -> Self {
157        Self::NotInvertible {
158            reason: reason.into(),
159        }
160    }
161
162    /// Create an eigenvalue error.
163    pub fn eigenvalue_error(reason: impl Into<String>) -> Self {
164        Self::EigenvalueError {
165            reason: reason.into(),
166        }
167    }
168
169    /// Create a spectral decomposition error.
170    pub fn spectral_decomposition_error(reason: impl Into<String>) -> Self {
171        Self::SpectralDecompositionError {
172            reason: reason.into(),
173        }
174    }
175
176    /// Create a Fredholm index undefined error.
177    pub fn fredholm_index_undefined(reason: impl Into<String>) -> Self {
178        Self::FredholmIndexUndefined {
179            reason: reason.into(),
180        }
181    }
182
183    /// Create a Sobolev error.
184    pub fn sobolev_error(description: impl Into<String>) -> Self {
185        Self::SobolevError {
186            description: description.into(),
187        }
188    }
189
190    /// Create a norm error.
191    pub fn norm_error(description: impl Into<String>) -> Self {
192        Self::NormError {
193            description: description.into(),
194        }
195    }
196
197    /// Create an inner product error.
198    pub fn inner_product_error(description: impl Into<String>) -> Self {
199        Self::InnerProductError {
200            description: description.into(),
201        }
202    }
203
204    /// Create a convergence error.
205    pub fn convergence_error(iterations: usize, reason: impl Into<String>) -> Self {
206        Self::ConvergenceError {
207            iterations,
208            reason: reason.into(),
209        }
210    }
211
212    /// Create a numerical instability error.
213    pub fn numerical_instability(operation: impl Into<String>, details: impl Into<String>) -> Self {
214        Self::NumericalInstability {
215            operation: operation.into(),
216            details: details.into(),
217        }
218    }
219
220    /// Create an invalid parameters error.
221    pub fn invalid_parameters(description: impl Into<String>) -> Self {
222        Self::InvalidParameters {
223            description: description.into(),
224        }
225    }
226}
227
228#[cfg(test)]
229mod tests {
230    use super::*;
231
232    #[test]
233    fn test_error_display() {
234        let err = FunctionalError::dimension_mismatch(8, 16);
235        assert_eq!(err.to_string(), "Dimension mismatch: expected 8, got 16");
236    }
237
238    #[test]
239    fn test_error_factory_methods() {
240        let err = FunctionalError::not_complete("Cauchy sequence does not converge");
241        assert!(matches!(err, FunctionalError::NotComplete { .. }));
242
243        let err = FunctionalError::eigenvalue_error("Matrix is singular");
244        assert!(matches!(err, FunctionalError::EigenvalueError { .. }));
245    }
246
247    #[test]
248    fn test_error_equality() {
249        let err1 = FunctionalError::dimension_mismatch(4, 8);
250        let err2 = FunctionalError::dimension_mismatch(4, 8);
251        let err3 = FunctionalError::dimension_mismatch(4, 16);
252
253        assert_eq!(err1, err2);
254        assert_ne!(err1, err3);
255    }
256}