Skip to main content

pounce_linsol/
error.rs

1//! Error type for the public [`crate::Factorization`] API.
2
3use crate::status::ESymSolverStatus;
4
5/// Outcome of a [`crate::Factorization`] operation.
6///
7/// Wraps the lower-level [`ESymSolverStatus`] with `Success` removed
8/// (success is expressed as `Result::Ok`). Variants mirror upstream
9/// Ipopt's status enum so a caller can map back if needed.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11pub enum FactorizationError {
12    /// Matrix is singular; factor was aborted.
13    Singular,
14    /// Backend's reported negative-eigenvalue count did not match the
15    /// caller's expectation.
16    WrongInertia,
17    /// Unrecoverable backend error.
18    FatalError,
19}
20
21impl FactorizationError {
22    /// Convert a backend status into a `Result`. `Success` becomes
23    /// `Ok(())`; `CallAgain` is treated as a fatal error here because
24    /// the public API drives the retry loop internally — a leaked
25    /// `CallAgain` indicates a backend bug.
26    pub(crate) fn from_status(status: ESymSolverStatus) -> Result<(), Self> {
27        match status {
28            ESymSolverStatus::Success => Ok(()),
29            ESymSolverStatus::Singular => Err(Self::Singular),
30            ESymSolverStatus::WrongInertia => Err(Self::WrongInertia),
31            ESymSolverStatus::CallAgain | ESymSolverStatus::FatalError => Err(Self::FatalError),
32        }
33    }
34}
35
36impl std::fmt::Display for FactorizationError {
37    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38        match self {
39            Self::Singular => write!(f, "matrix is singular"),
40            Self::WrongInertia => write!(f, "factorization inertia did not match expectation"),
41            Self::FatalError => write!(f, "fatal linear-solver error"),
42        }
43    }
44}
45
46impl std::error::Error for FactorizationError {}