#[allow(unused_imports)]
use crate::algebra::blas::{dot_conj, nrm2};
use crate::algebra::prelude::*;
#[inline]
pub fn build_complex_givens(a: S, b: S) -> (R, S) {
let absa = a.abs();
let absb = b.abs();
if absb <= R::default() {
return (1.0, S::zero());
}
if absa <= R::default() {
return (0.0, b.conj() / S::from_real(absb));
}
let r = absa.hypot(absb);
let c = absa / r;
let s = (a * b.conj()) / S::from_real(r * absa);
(c, s)
}
#[inline]
pub fn apply_complex_givens(h_ik: &mut S, h_ip1k: &mut S, c: R, s: S) {
let c_s = S::from_real(c);
let t = c_s * *h_ik + s * *h_ip1k;
let t2 = -s.conj() * *h_ik + c_s * *h_ip1k;
*h_ik = t;
*h_ip1k = t2;
}
#[inline]
pub fn apply_prev_givens_to_col(hcol: &mut [S], k: usize, cs: &[R], sn: &[S]) {
for i in 0..k {
let (head, tail) = hcol.split_at_mut(i + 1);
let hij = &mut head[i];
let hij1 = &mut tail[0];
apply_complex_givens(hij, hij1, cs[i], sn[i]);
}
}
#[inline]
pub fn apply_new_givens_and_update_g(
hcol: &mut [S],
k: usize,
cs: &mut [R],
sn: &mut [S],
g: &mut [S],
) {
let (c, s) = build_complex_givens(hcol[k], hcol[k + 1]);
cs[k] = c;
sn[k] = s;
let (head, tail) = hcol.split_at_mut(k + 1);
let hik = &mut head[k];
let hip1k = &mut tail[0];
apply_complex_givens(hik, hip1k, c, s);
let c_s = S::from_real(c);
let gk = g[k];
let gk1 = g[k + 1];
g[k] = c_s * gk + s * gk1;
g[k + 1] = -s.conj() * gk + c_s * gk1;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn complex_givens_zeroes_second_entry() {
let a: S = S::from_real(1.2);
#[cfg(feature = "complex")]
let b: S = num_complex::Complex64::new(-0.7, 0.5);
#[cfg(not(feature = "complex"))]
let b: S = S::from_real(-0.7);
let (c, s) = build_complex_givens(a, b);
let mut h0 = a;
let mut h1 = b;
apply_complex_givens(&mut h0, &mut h1, c, s);
let scale = (a.abs() + b.abs()).max(1.0);
assert!(h1.abs() <= 1e-12 * scale);
assert!(c >= 0.0);
}
#[test]
fn givens_handles_zero_head_entry() {
let a = S::zero();
#[cfg(feature = "complex")]
let b: S = num_complex::Complex64::new(0.3, -0.4);
#[cfg(not(feature = "complex"))]
let b: S = S::from_real(-0.4);
let (c, s) = build_complex_givens(a, b);
let mut h0 = a;
let mut h1 = b;
apply_complex_givens(&mut h0, &mut h1, c, s);
assert!(c.abs() <= 1e-14);
assert!((h0.abs() - b.abs()).abs() <= 1e-12 * b.abs().max(1.0));
assert!(h1.abs() <= 1e-12 * b.abs().max(1.0));
}
}