use core::fmt;
pub type NumraResult<T> = Result<T, NumraError>;
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub enum NumraError {
Linalg(LinalgError),
Convergence(ConvergenceError),
InvalidInput(String),
StepSizeTooSmall { h: f64, h_min: f64 },
MaxIterations { iterations: usize, max: usize },
Stiffness { t: f64, message: String },
EventTermination { t: f64, event_index: usize },
NumericalOptim(OptimizationError),
Ode(String),
Optim(String),
Ocp(String),
Fit(String),
Signal(String),
LineSearch(String),
Interp(String),
Integrate(String),
Special(String),
Stats(String),
}
impl fmt::Display for NumraError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NumraError::Linalg(e) => write!(f, "Linear algebra error: {}", e),
NumraError::Convergence(e) => write!(f, "Convergence error: {}", e),
NumraError::InvalidInput(msg) => write!(f, "Invalid input: {}", msg),
NumraError::StepSizeTooSmall { h, h_min } => {
write!(f, "Step size {} below minimum {}", h, h_min)
}
NumraError::MaxIterations { iterations, max } => {
write!(f, "Maximum iterations ({}) exceeded at {}", max, iterations)
}
NumraError::Stiffness { t, message } => {
write!(f, "Stiffness detected at t={}: {}", t, message)
}
NumraError::EventTermination { t, event_index } => {
write!(f, "Event {} terminated integration at t={}", event_index, t)
}
NumraError::NumericalOptim(e) => write!(f, "Numerical optimization error: {}", e),
NumraError::Ode(s) => write!(f, "ODE error: {}", s),
NumraError::Optim(s) => write!(f, "Optimization error: {}", s),
NumraError::Ocp(s) => write!(f, "OCP error: {}", s),
NumraError::Fit(s) => write!(f, "Fit error: {}", s),
NumraError::Signal(s) => write!(f, "Signal error: {}", s),
NumraError::LineSearch(s) => write!(f, "Line search error: {}", s),
NumraError::Interp(s) => write!(f, "Interpolation error: {}", s),
NumraError::Integrate(s) => write!(f, "Integration error: {}", s),
NumraError::Special(s) => write!(f, "Special function error: {}", s),
NumraError::Stats(s) => write!(f, "Statistics error: {}", s),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for NumraError {}
#[derive(Clone, Debug, PartialEq)]
pub enum LinalgError {
Singular { step: usize },
DimensionMismatch {
expected: (usize, usize),
actual: (usize, usize),
},
NotSquare { nrows: usize, ncols: usize },
NotPositiveDefinite,
IterativeNotConverged { iterations: usize, residual: f64 },
EigenDecompositionFailed,
SvdFailed,
}
impl fmt::Display for LinalgError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LinalgError::Singular { step } => {
write!(f, "Matrix is singular (detected at step {})", step)
}
LinalgError::DimensionMismatch { expected, actual } => {
write!(
f,
"Dimension mismatch: expected {:?}, got {:?}",
expected, actual
)
}
LinalgError::NotSquare { nrows, ncols } => {
write!(f, "Matrix is not square: {}x{}", nrows, ncols)
}
LinalgError::NotPositiveDefinite => {
write!(f, "Matrix is not positive definite")
}
LinalgError::IterativeNotConverged {
iterations,
residual,
} => {
write!(
f,
"Iterative solver did not converge after {} iterations (residual: {})",
iterations, residual
)
}
LinalgError::EigenDecompositionFailed => {
write!(f, "Eigenvalue decomposition failed")
}
LinalgError::SvdFailed => {
write!(f, "SVD computation failed")
}
}
}
}
impl From<LinalgError> for NumraError {
fn from(e: LinalgError) -> Self {
NumraError::Linalg(e)
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum ConvergenceError {
Newton { iterations: usize, residual: f64 },
FixedPoint { iterations: usize, delta: f64 },
}
impl fmt::Display for ConvergenceError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ConvergenceError::Newton {
iterations,
residual,
} => {
write!(
f,
"Newton iteration did not converge after {} iterations (residual: {})",
iterations, residual
)
}
ConvergenceError::FixedPoint { iterations, delta } => {
write!(
f,
"Fixed point iteration did not converge after {} iterations (delta: {})",
iterations, delta
)
}
}
}
}
impl From<ConvergenceError> for NumraError {
fn from(e: ConvergenceError) -> Self {
NumraError::Convergence(e)
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum OptimizationError {
LineSearchFailed { iterations: usize, step_size: f64 },
NotDescentDirection { directional_derivative: f64 },
NotConverged {
iterations: usize,
gradient_norm: f64,
},
InvalidFunctionValue { value: f64 },
}
impl fmt::Display for OptimizationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
OptimizationError::LineSearchFailed {
iterations,
step_size,
} => {
write!(
f,
"Line search failed after {} iterations (step size: {})",
iterations, step_size
)
}
OptimizationError::NotDescentDirection {
directional_derivative,
} => {
write!(
f,
"Search direction is not a descent direction (directional derivative: {})",
directional_derivative
)
}
OptimizationError::NotConverged {
iterations,
gradient_norm,
} => {
write!(
f,
"Optimization did not converge after {} iterations (gradient norm: {})",
iterations, gradient_norm
)
}
OptimizationError::InvalidFunctionValue { value } => {
write!(f, "Function evaluation returned invalid value: {}", value)
}
}
}
}
impl From<OptimizationError> for NumraError {
fn from(e: OptimizationError) -> Self {
NumraError::NumericalOptim(e)
}
}