#![forbid(unsafe_code)]
#![deny(missing_docs)]
#![doc = include_str!("../README.md")]
#[cfg(doc)]
mod readme_doctests {
fn solve_5x5_example() {}
fn det_5x5_ldlt_example() {}
fn det_direct_4x4_const_example() {}
#[cfg(feature = "exact")]
fn exact_arithmetic_example() {}
#[cfg(feature = "exact")]
fn adaptive_precision_example() {}
}
mod error;
#[cfg(feature = "exact")]
mod exact;
mod ldlt;
mod lu;
mod matrix;
mod scaled_product;
mod tolerance;
mod vector;
#[cfg(feature = "exact")]
pub use exact::{DeterminantSign, ExactF64Conversion};
#[cfg(feature = "exact")]
pub use num_bigint::BigInt;
#[cfg(feature = "exact")]
pub use num_rational::BigRational;
#[cfg(feature = "exact")]
pub use num_traits::{FromPrimitive, Signed, ToPrimitive};
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 MAX_STACK_MATRIX_DISPATCH_DIM: usize = 7;
pub use error::{
ArithmeticOperation, FactorizationKind, InvalidToleranceReason, LaError, NonFiniteLocation,
NonFiniteOrigin, PositiveSemidefiniteViolation, SingularityReason, UnrepresentableReason,
};
pub use ldlt::Ldlt;
pub use lu::Lu;
pub use matrix::{DeterminantWithErrorBound, Matrix};
pub use tolerance::{DEFAULT_SINGULAR_TOL, Tolerance};
pub use vector::Vector;
#[macro_export]
macro_rules! try_with_stack_matrix {
($dim:expr, |$matrix:ident| -> $ret:ty $body:block $(,)?) => {{
let __la_stack_requested_dim: usize = $dim;
match __la_stack_requested_dim {
0 => $crate::try_with_stack_matrix!(@arm 0, $matrix, $ret, $body),
1 => $crate::try_with_stack_matrix!(@arm 1, $matrix, $ret, $body),
2 => $crate::try_with_stack_matrix!(@arm 2, $matrix, $ret, $body),
3 => $crate::try_with_stack_matrix!(@arm 3, $matrix, $ret, $body),
4 => $crate::try_with_stack_matrix!(@arm 4, $matrix, $ret, $body),
5 => $crate::try_with_stack_matrix!(@arm 5, $matrix, $ret, $body),
6 => $crate::try_with_stack_matrix!(@arm 6, $matrix, $ret, $body),
7 => $crate::try_with_stack_matrix!(@arm 7, $matrix, $ret, $body),
requested => Err(::core::convert::From::from(
$crate::LaError::unsupported_dimension(
requested,
$crate::MAX_STACK_MATRIX_DISPATCH_DIM,
),
)),
}
}};
($dim:expr, |mut $matrix:ident| -> $ret:ty $body:block $(,)?) => {{
let __la_stack_requested_dim: usize = $dim;
match __la_stack_requested_dim {
0 => $crate::try_with_stack_matrix!(@arm_mut 0, $matrix, $ret, $body),
1 => $crate::try_with_stack_matrix!(@arm_mut 1, $matrix, $ret, $body),
2 => $crate::try_with_stack_matrix!(@arm_mut 2, $matrix, $ret, $body),
3 => $crate::try_with_stack_matrix!(@arm_mut 3, $matrix, $ret, $body),
4 => $crate::try_with_stack_matrix!(@arm_mut 4, $matrix, $ret, $body),
5 => $crate::try_with_stack_matrix!(@arm_mut 5, $matrix, $ret, $body),
6 => $crate::try_with_stack_matrix!(@arm_mut 6, $matrix, $ret, $body),
7 => $crate::try_with_stack_matrix!(@arm_mut 7, $matrix, $ret, $body),
requested => Err(::core::convert::From::from(
$crate::LaError::unsupported_dimension(
requested,
$crate::MAX_STACK_MATRIX_DISPATCH_DIM,
),
)),
}
}};
(@arm $d:literal, $matrix:ident, $ret:ty, $body:block) => {{
let __la_stack_body = |$matrix: $crate::Matrix<$d>| -> $ret { $body };
__la_stack_body($crate::Matrix::<$d>::zero())
}};
(@arm_mut $d:literal, $matrix:ident, $ret:ty, $body:block) => {{
let __la_stack_body = |mut $matrix: $crate::Matrix<$d>| -> $ret { $body };
__la_stack_body($crate::Matrix::<$d>::zero())
}};
}
pub mod prelude {
pub use crate::{
ArithmeticOperation, DEFAULT_SINGULAR_TOL, DeterminantWithErrorBound, FactorizationKind,
InvalidToleranceReason, LaError, Ldlt, Lu, MAX_STACK_MATRIX_DISPATCH_DIM, Matrix,
NonFiniteLocation, NonFiniteOrigin, PositiveSemidefiniteViolation, SingularityReason,
Tolerance, UnrepresentableReason, Vector, try_with_stack_matrix,
};
#[cfg(feature = "exact")]
pub use crate::{
BigInt, BigRational, DeterminantSign, ExactF64Conversion, FromPrimitive, Signed,
ToPrimitive,
};
}
#[cfg(test)]
mod tests {
use approx::assert_abs_diff_eq;
use pastey::paste;
use super::*;
macro_rules! gen_stack_matrix_dispatch_tests {
($d:literal) => {
paste! {
#[test]
fn [<try_with_stack_matrix_dispatches_ $d d>]() {
let requested = $d;
let got = try_with_stack_matrix!(requested, |mut m| -> Result<usize, LaError> {
if $d > 0 {
m.set($d - 1, $d - 1, f64::from($d))?;
assert_abs_diff_eq!(
m.try_get($d - 1, $d - 1)?,
f64::from($d),
epsilon = 0.0
);
}
Ok($d)
});
assert_eq!(got, Ok($d));
}
}
};
}
gen_stack_matrix_dispatch_tests!(1);
gen_stack_matrix_dispatch_tests!(2);
gen_stack_matrix_dispatch_tests!(3);
gen_stack_matrix_dispatch_tests!(4);
gen_stack_matrix_dispatch_tests!(5);
gen_stack_matrix_dispatch_tests!(6);
gen_stack_matrix_dispatch_tests!(7);
#[test]
fn try_with_stack_matrix_supports_zero_dimension() {
let got = try_with_stack_matrix!(0usize, |m| -> Result<Option<f64>, LaError> {
m.det_direct()
});
assert_eq!(got, Ok(Some(1.0)));
}
#[test]
fn try_with_stack_matrix_evaluates_dimension_once() {
let mut evaluations = 0;
let got = try_with_stack_matrix!(
{
evaluations += 1;
2usize
},
|matrix| -> Result<f64, LaError> { matrix.try_get(1, 1) },
);
assert_eq!(evaluations, 1);
assert_eq!(got, Ok(0.0));
}
#[test]
fn try_with_stack_matrix_reports_unsupported_dimension() {
let got = try_with_stack_matrix!(8usize, |m| -> Result<f64, LaError> { m.det() });
assert_eq!(
got,
Err(LaError::UnsupportedDimension {
requested: 8,
max: MAX_STACK_MATRIX_DISPATCH_DIM,
})
);
}
#[derive(Debug, PartialEq)]
struct DownstreamError(LaError);
impl From<LaError> for DownstreamError {
fn from(err: LaError) -> Self {
Self(err)
}
}
#[test]
fn try_with_stack_matrix_converts_unsupported_dimension_error() {
let got = try_with_stack_matrix!(9usize, |m| -> Result<usize, DownstreamError> {
assert_abs_diff_eq!(m.inf_norm()?, 0.0, epsilon = 0.0);
Ok(0)
});
assert_eq!(
got,
Err(DownstreamError(LaError::UnsupportedDimension {
requested: 9,
max: MAX_STACK_MATRIX_DISPATCH_DIM,
}))
);
}
}