use nalgebra::{allocator::Allocator, DefaultAllocator, Dim, OMatrix, RealField};
pub fn rcond_symmetric<N: Copy + RealField, R: Dim, C: Dim>(sm: &OMatrix<N, R, C>) -> N
where
DefaultAllocator: Allocator<R, C>,
{
let n = sm.nrows();
if n == 0 {
N::zero()
} else {
let mut mind = sm[(0, 0)];
let mut maxd = mind;
for i in 0..n {
let d = sm[(i, i)];
if d != d {
mind = N::one().neg();
break;
}
if d < mind {
mind = d;
}
if d > maxd {
maxd = d;
}
}
rcond_min_max(mind, maxd)
}
}
fn rcond_min_max<N: RealField>(mind: N, maxd: N) -> N {
if mind < N::zero() {
mind } else {
assert!(mind <= maxd);
let rcond = mind / maxd; if !rcond.is_finite() {
N::zero()
} else {
assert!(rcond <= N::one());
rcond
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_simple_rconds() {
assert_eq!(rcond_min_max(1., 1.), 1.);
assert_eq!(rcond_min_max(1., 2.), 0.5);
}
#[test]
fn test_special_rconds() {
assert_eq!(rcond_min_max(-1., 55.), -1.);
assert_eq!(rcond_min_max(-2.,55.), -2.);
assert_eq!(rcond_min_max(-0.,55.), -0.);
assert_eq!(rcond_min_max(-0., 0.), 0.);
assert_eq!(rcond_min_max(-0., -0.), 0.);
}
#[should_panic(expected = "mind <= maxd")]
#[test]
fn test_greater_one_panics() {
rcond_min_max(2., 1.);
}
}
pub fn check_positive<N: RealField>(rcond: N, message: &str) -> Result<(), &str> {
if rcond > N::zero() {
Ok(())
} else {
Err(message)
}
}
pub fn check_non_negative<N: RealField>(rcond: N, message: &str) -> Result<(), &str> {
if rcond >= N::zero() {
Ok(())
} else {
Err(message)
}
}