amari_functional/
error.rs1use thiserror::Error;
8
9pub type Result<T> = core::result::Result<T, FunctionalError>;
11
12#[derive(Error, Debug, Clone, PartialEq)]
14pub enum FunctionalError {
15 #[error("Dimension mismatch: expected {expected}, got {actual}")]
17 DimensionMismatch {
18 expected: usize,
20 actual: usize,
22 },
23
24 #[error("Space is not complete: {reason}")]
26 NotComplete {
27 reason: String,
29 },
30
31 #[error("Operator is not bounded: {description}")]
33 NotBounded {
34 description: String,
36 },
37
38 #[error("Operator is not compact: {reason}")]
40 NotCompact {
41 reason: String,
43 },
44
45 #[error("Operator is not invertible: {reason}")]
47 NotInvertible {
48 reason: String,
50 },
51
52 #[error("Eigenvalue computation failed: {reason}")]
54 EigenvalueError {
55 reason: String,
57 },
58
59 #[error("Spectral decomposition failed: {reason}")]
61 SpectralDecompositionError {
62 reason: String,
64 },
65
66 #[error("Fredholm index undefined: {reason}")]
68 FredholmIndexUndefined {
69 reason: String,
71 },
72
73 #[error("Sobolev space error: {description}")]
75 SobolevError {
76 description: String,
78 },
79
80 #[error("Norm error: {description}")]
82 NormError {
83 description: String,
85 },
86
87 #[error("Inner product error: {description}")]
89 InnerProductError {
90 description: String,
92 },
93
94 #[error("Convergence failed after {iterations} iterations: {reason}")]
96 ConvergenceError {
97 iterations: usize,
99 reason: String,
101 },
102
103 #[error("Numerical instability in {operation}: {details}")]
105 NumericalInstability {
106 operation: String,
108 details: String,
110 },
111
112 #[error("Invalid parameters: {description}")]
114 InvalidParameters {
115 description: String,
117 },
118
119 #[error(transparent)]
121 MeasureError(#[from] amari_measure::MeasureError),
122
123 #[error(transparent)]
125 CalculusError(#[from] amari_calculus::CalculusError),
126}
127
128impl FunctionalError {
129 pub fn dimension_mismatch(expected: usize, actual: usize) -> Self {
131 Self::DimensionMismatch { expected, actual }
132 }
133
134 pub fn not_complete(reason: impl Into<String>) -> Self {
136 Self::NotComplete {
137 reason: reason.into(),
138 }
139 }
140
141 pub fn not_bounded(description: impl Into<String>) -> Self {
143 Self::NotBounded {
144 description: description.into(),
145 }
146 }
147
148 pub fn not_compact(reason: impl Into<String>) -> Self {
150 Self::NotCompact {
151 reason: reason.into(),
152 }
153 }
154
155 pub fn not_invertible(reason: impl Into<String>) -> Self {
157 Self::NotInvertible {
158 reason: reason.into(),
159 }
160 }
161
162 pub fn eigenvalue_error(reason: impl Into<String>) -> Self {
164 Self::EigenvalueError {
165 reason: reason.into(),
166 }
167 }
168
169 pub fn spectral_decomposition_error(reason: impl Into<String>) -> Self {
171 Self::SpectralDecompositionError {
172 reason: reason.into(),
173 }
174 }
175
176 pub fn fredholm_index_undefined(reason: impl Into<String>) -> Self {
178 Self::FredholmIndexUndefined {
179 reason: reason.into(),
180 }
181 }
182
183 pub fn sobolev_error(description: impl Into<String>) -> Self {
185 Self::SobolevError {
186 description: description.into(),
187 }
188 }
189
190 pub fn norm_error(description: impl Into<String>) -> Self {
192 Self::NormError {
193 description: description.into(),
194 }
195 }
196
197 pub fn inner_product_error(description: impl Into<String>) -> Self {
199 Self::InnerProductError {
200 description: description.into(),
201 }
202 }
203
204 pub fn convergence_error(iterations: usize, reason: impl Into<String>) -> Self {
206 Self::ConvergenceError {
207 iterations,
208 reason: reason.into(),
209 }
210 }
211
212 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 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}