use crate::core::math::Scalar;
pub(crate) fn dot<F: Scalar>(a: &[F], b: &[F]) -> F {
a.iter().zip(b).map(|(&x, &y)| x * y).sum()
}
pub(crate) fn col<F>(a: &[F], r: usize, j: usize) -> &[F] {
&a[j * r..(j + 1) * r]
}
pub(crate) fn row_times_mat<F: Scalar>(x: &[F], a: &[F], r: usize, c: usize) -> Vec<F> {
(0..c).map(|j| dot(x, col(a, r, j))).collect()
}
pub(crate) fn eye<F: Scalar>(n: usize) -> Vec<F> {
let mut q = vec![F::zero(); n * n];
for i in 0..n {
q[i + i * n] = F::one();
}
q
}
pub(crate) fn fsign<F: Scalar>(a: F, b: F) -> F {
if b >= F::zero() { a.abs() } else { -a.abs() }
}
pub(crate) fn hypotenuse<F: Scalar>(x0: F, x1: F) -> F {
let (a, b) = (x0.abs(), x1.abs());
let (lo, hi) = if a < b { (a, b) } else { (b, a) };
if hi <= F::zero() {
F::zero()
} else {
let t = lo / hi;
hi * (t * t + F::one()).sqrt()
}
}
pub(crate) fn isminor<F: Scalar>(x: F, refv: F) -> bool {
let sensitivity = F::from_f64(0.1).unwrap();
let two = F::from_f64(2.0).unwrap();
let refa = refv.abs() + sensitivity * x.abs();
let refb = refv.abs() + two * sensitivity * x.abs();
refv.abs() >= refa || refa >= refb
}
pub(crate) fn planerot<F: Scalar>(x0: F, x1: F) -> (F, F) {
let zero = F::zero();
let one = F::one();
let eps = F::epsilon();
if x0.is_nan() || x1.is_nan() {
return (one, zero);
}
if x0.is_infinite() && x1.is_infinite() {
let r = one / (one + one).sqrt();
return (fsign(r, x0), fsign(r, x1));
}
if x0.abs() <= zero && x1.abs() <= zero {
return (one, zero);
}
if x1.abs() <= eps * x0.abs() {
return (fsign(one, x0), zero);
}
if x0.abs() <= eps * x1.abs() {
return (zero, fsign(one, x1));
}
if x0.abs() > x1.abs() {
let t = x1 / x0;
let u = fsign((one + t * t).sqrt(), x0);
(one / u, t / u)
} else {
let t = x0 / x1;
let u = fsign((one + t * t).sqrt(), x1);
(t / u, one / u)
}
}
pub(crate) fn inv<F: Scalar>(a: &[F], n: usize) -> Option<Vec<F>> {
let mut m = a.to_vec(); let mut out = eye::<F>(n);
for c in 0..n {
let mut piv = c;
let mut best = m[c + c * n].abs();
for r in (c + 1)..n {
let v = m[r + c * n].abs();
if v > best {
best = v;
piv = r;
}
}
if best <= F::zero() || !best.is_finite() {
return None;
}
if piv != c {
for j in 0..n {
m.swap(c + j * n, piv + j * n);
out.swap(c + j * n, piv + j * n);
}
}
let d = m[c + c * n];
for j in 0..n {
m[c + j * n] = m[c + j * n] / d;
out[c + j * n] = out[c + j * n] / d;
}
for r in 0..n {
if r == c {
continue;
}
let f = m[r + c * n];
if f == F::zero() {
continue;
}
for j in 0..n {
m[r + j * n] = m[r + j * n] - f * m[c + j * n];
out[r + j * n] = out[r + j * n] - f * out[c + j * n];
}
}
}
Some(out)
}
pub(crate) fn maxabs<F: Scalar>(a: &[F]) -> F {
a.iter().fold(F::zero(), |acc, &x| {
if x.is_nan() {
F::nan()
} else {
acc.max(x.abs())
}
})
}