1use core::fmt;
10
11pub type NumraResult<T> = Result<T, NumraError>;
13
14#[derive(Clone, Debug, PartialEq)]
53#[non_exhaustive]
54pub enum NumraError {
55 Linalg(LinalgError),
57 Convergence(ConvergenceError),
59 InvalidInput(String),
61 StepSizeTooSmall { h: f64, h_min: f64 },
63 MaxIterations { iterations: usize, max: usize },
65 Stiffness { t: f64, message: String },
67 EventTermination { t: f64, event_index: usize },
69 NumericalOptim(OptimizationError),
72 Ode(String),
74 Optim(String),
76 Ocp(String),
78 Fit(String),
80 Signal(String),
82 LineSearch(String),
84 Interp(String),
86 Integrate(String),
88 Special(String),
90 Stats(String),
92}
93
94impl fmt::Display for NumraError {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 match self {
97 NumraError::Linalg(e) => write!(f, "Linear algebra error: {}", e),
98 NumraError::Convergence(e) => write!(f, "Convergence error: {}", e),
99 NumraError::InvalidInput(msg) => write!(f, "Invalid input: {}", msg),
100 NumraError::StepSizeTooSmall { h, h_min } => {
101 write!(f, "Step size {} below minimum {}", h, h_min)
102 }
103 NumraError::MaxIterations { iterations, max } => {
104 write!(f, "Maximum iterations ({}) exceeded at {}", max, iterations)
105 }
106 NumraError::Stiffness { t, message } => {
107 write!(f, "Stiffness detected at t={}: {}", t, message)
108 }
109 NumraError::EventTermination { t, event_index } => {
110 write!(f, "Event {} terminated integration at t={}", event_index, t)
111 }
112 NumraError::NumericalOptim(e) => write!(f, "Numerical optimization error: {}", e),
113 NumraError::Ode(s) => write!(f, "ODE error: {}", s),
114 NumraError::Optim(s) => write!(f, "Optimization error: {}", s),
115 NumraError::Ocp(s) => write!(f, "OCP error: {}", s),
116 NumraError::Fit(s) => write!(f, "Fit error: {}", s),
117 NumraError::Signal(s) => write!(f, "Signal error: {}", s),
118 NumraError::LineSearch(s) => write!(f, "Line search error: {}", s),
119 NumraError::Interp(s) => write!(f, "Interpolation error: {}", s),
120 NumraError::Integrate(s) => write!(f, "Integration error: {}", s),
121 NumraError::Special(s) => write!(f, "Special function error: {}", s),
122 NumraError::Stats(s) => write!(f, "Statistics error: {}", s),
123 }
124 }
125}
126
127#[cfg(feature = "std")]
128impl std::error::Error for NumraError {}
129
130#[derive(Clone, Debug, PartialEq)]
132pub enum LinalgError {
133 Singular { step: usize },
135 DimensionMismatch {
137 expected: (usize, usize),
138 actual: (usize, usize),
139 },
140 NotSquare { nrows: usize, ncols: usize },
142 NotPositiveDefinite,
144 IterativeNotConverged { iterations: usize, residual: f64 },
146 EigenDecompositionFailed,
148 SvdFailed,
150}
151
152impl fmt::Display for LinalgError {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 match self {
155 LinalgError::Singular { step } => {
156 write!(f, "Matrix is singular (detected at step {})", step)
157 }
158 LinalgError::DimensionMismatch { expected, actual } => {
159 write!(
160 f,
161 "Dimension mismatch: expected {:?}, got {:?}",
162 expected, actual
163 )
164 }
165 LinalgError::NotSquare { nrows, ncols } => {
166 write!(f, "Matrix is not square: {}x{}", nrows, ncols)
167 }
168 LinalgError::NotPositiveDefinite => {
169 write!(f, "Matrix is not positive definite")
170 }
171 LinalgError::IterativeNotConverged {
172 iterations,
173 residual,
174 } => {
175 write!(
176 f,
177 "Iterative solver did not converge after {} iterations (residual: {})",
178 iterations, residual
179 )
180 }
181 LinalgError::EigenDecompositionFailed => {
182 write!(f, "Eigenvalue decomposition failed")
183 }
184 LinalgError::SvdFailed => {
185 write!(f, "SVD computation failed")
186 }
187 }
188 }
189}
190
191impl From<LinalgError> for NumraError {
192 fn from(e: LinalgError) -> Self {
193 NumraError::Linalg(e)
194 }
195}
196
197#[derive(Clone, Debug, PartialEq)]
199pub enum ConvergenceError {
200 Newton { iterations: usize, residual: f64 },
202 FixedPoint { iterations: usize, delta: f64 },
204}
205
206impl fmt::Display for ConvergenceError {
207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208 match self {
209 ConvergenceError::Newton {
210 iterations,
211 residual,
212 } => {
213 write!(
214 f,
215 "Newton iteration did not converge after {} iterations (residual: {})",
216 iterations, residual
217 )
218 }
219 ConvergenceError::FixedPoint { iterations, delta } => {
220 write!(
221 f,
222 "Fixed point iteration did not converge after {} iterations (delta: {})",
223 iterations, delta
224 )
225 }
226 }
227 }
228}
229
230impl From<ConvergenceError> for NumraError {
231 fn from(e: ConvergenceError) -> Self {
232 NumraError::Convergence(e)
233 }
234}
235
236#[derive(Clone, Debug, PartialEq)]
238pub enum OptimizationError {
239 LineSearchFailed { iterations: usize, step_size: f64 },
241 NotDescentDirection { directional_derivative: f64 },
243 NotConverged {
245 iterations: usize,
246 gradient_norm: f64,
247 },
248 InvalidFunctionValue { value: f64 },
250}
251
252impl fmt::Display for OptimizationError {
253 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254 match self {
255 OptimizationError::LineSearchFailed {
256 iterations,
257 step_size,
258 } => {
259 write!(
260 f,
261 "Line search failed after {} iterations (step size: {})",
262 iterations, step_size
263 )
264 }
265 OptimizationError::NotDescentDirection {
266 directional_derivative,
267 } => {
268 write!(
269 f,
270 "Search direction is not a descent direction (directional derivative: {})",
271 directional_derivative
272 )
273 }
274 OptimizationError::NotConverged {
275 iterations,
276 gradient_norm,
277 } => {
278 write!(
279 f,
280 "Optimization did not converge after {} iterations (gradient norm: {})",
281 iterations, gradient_norm
282 )
283 }
284 OptimizationError::InvalidFunctionValue { value } => {
285 write!(f, "Function evaluation returned invalid value: {}", value)
286 }
287 }
288 }
289}
290
291impl From<OptimizationError> for NumraError {
292 fn from(e: OptimizationError) -> Self {
293 NumraError::NumericalOptim(e)
294 }
295}