#![forbid(unsafe_code)]
#![warn(missing_docs)]
#![doc = include_str!("../README.md")]
#[cfg(doc)]
mod readme_doctests {
fn solve_5x5_example() {}
fn det_5x5_ldlt_example() {}
}
#[cfg(feature = "exact")]
mod exact;
#[cfg(feature = "exact")]
pub use num_rational::BigRational;
mod ldlt;
mod lu;
mod matrix;
mod vector;
use core::fmt;
const EPS: f64 = f64::EPSILON;
pub const ERR_COEFF_2: f64 = 3.0 * EPS + 16.0 * EPS * EPS;
pub const ERR_COEFF_3: f64 = 8.0 * EPS + 64.0 * EPS * EPS;
pub const ERR_COEFF_4: f64 = 12.0 * EPS + 128.0 * EPS * EPS;
pub const DEFAULT_SINGULAR_TOL: f64 = 1e-12;
pub const DEFAULT_PIVOT_TOL: f64 = DEFAULT_SINGULAR_TOL;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum LaError {
Singular {
pivot_col: usize,
},
NonFinite {
row: Option<usize>,
col: usize,
},
Overflow {
index: Option<usize>,
},
}
impl fmt::Display for LaError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Self::Singular { pivot_col } => {
write!(f, "singular matrix at pivot column {pivot_col}")
}
Self::NonFinite { row: Some(r), col } => {
write!(f, "non-finite value at ({r}, {col})")
}
Self::NonFinite { row: None, col } => {
write!(f, "non-finite value at index {col}")
}
Self::Overflow { index: Some(i) } => {
write!(
f,
"exact result overflows the target representation at index {i}"
)
}
Self::Overflow { index: None } => {
write!(f, "exact result overflows the target representation")
}
}
}
}
impl std::error::Error for LaError {}
pub use ldlt::Ldlt;
pub use lu::Lu;
pub use matrix::Matrix;
pub use vector::Vector;
pub mod prelude {
pub use crate::{
DEFAULT_PIVOT_TOL, DEFAULT_SINGULAR_TOL, ERR_COEFF_2, ERR_COEFF_3, ERR_COEFF_4, LaError,
Ldlt, Lu, Matrix, Vector,
};
#[cfg(feature = "exact")]
pub use crate::BigRational;
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_abs_diff_eq;
#[test]
fn default_singular_tol_is_expected() {
assert_abs_diff_eq!(DEFAULT_SINGULAR_TOL, 1e-12, epsilon = 0.0);
assert_abs_diff_eq!(DEFAULT_PIVOT_TOL, DEFAULT_SINGULAR_TOL, epsilon = 0.0);
}
#[test]
fn laerror_display_formats_singular() {
let err = LaError::Singular { pivot_col: 3 };
assert_eq!(err.to_string(), "singular matrix at pivot column 3");
}
#[test]
fn laerror_display_formats_nonfinite_with_row() {
let err = LaError::NonFinite {
row: Some(1),
col: 2,
};
assert_eq!(err.to_string(), "non-finite value at (1, 2)");
}
#[test]
fn laerror_display_formats_nonfinite_without_row() {
let err = LaError::NonFinite { row: None, col: 3 };
assert_eq!(err.to_string(), "non-finite value at index 3");
}
#[test]
fn laerror_display_formats_overflow() {
let err = LaError::Overflow { index: None };
assert_eq!(
err.to_string(),
"exact result overflows the target representation"
);
}
#[test]
fn laerror_display_formats_overflow_with_index() {
let err = LaError::Overflow { index: Some(2) };
assert_eq!(
err.to_string(),
"exact result overflows the target representation at index 2"
);
}
#[test]
fn laerror_is_std_error_with_no_source() {
let err = LaError::Singular { pivot_col: 0 };
let e: &dyn std::error::Error = &err;
assert!(e.source().is_none());
}
#[test]
fn prelude_reexports_compile_and_work() {
use crate::prelude::*;
let m = Matrix::<2>::identity();
let v = Vector::<2>::new([1.0, 2.0]);
let _ = m.lu(DEFAULT_PIVOT_TOL).unwrap().solve_vec(v).unwrap();
let _ = m.ldlt(DEFAULT_SINGULAR_TOL).unwrap().solve_vec(v).unwrap();
}
}