fn scalar_q(
packed: MatRef<'_, Scalar>,
coeff: MatRef<'_, Scalar>,
) -> Mat<Scalar> {
let m = packed.nrows();
let k = coeff.ncols();
let bs = coeff.nrows();
let mut q = Mat::<Scalar>::identity(m, m);
for r in (0..k).rev() {
let tau = real(&coeff[(r % bs, r)]);
let inv = 1.0 / tau;
if inv == 0.0 {
continue;
}
for j in 0..m {
let mut dot = q[(r, j)];
for i in r + 1..m {
dot += conj(&packed[(i, r)]) * q[(i, j)];
}
dot *= inv;
q[(r, j)] -= dot;
for i in r + 1..m {
q[(i, j)] -= packed[(i, r)] * dot;
}
}
}
q
}
fn qr_fixture(m: usize, n: usize, kind: usize) -> Mat<Scalar> {
if kind == 0 {
return Mat::zeros(m, n);
}
if kind == 4 {
return Mat::from_fn(m, n, |i, j| phase(i) * (j + 1) as Real);
}
let scale = match kind {
6 => Real::MAX.sqrt() / 16.0,
7 => Real::MIN_POSITIVE.sqrt() * 16.0,
_ => 1.0,
};
let q = unitary(m);
let v = unitary(n);
let d = Mat::from_fn(m, n, |i, j| {
if i == j {
z(scale
* match kind {
1 => 1.0,
2 => 1.0 + i as Real / m.min(n).max(1) as Real,
3 => Real::EPSILON
.sqrt()
.powf(i as Real / m.min(n).max(1) as Real),
5 => {
if i + 1 == m.min(n) {
0.0
} else {
1.0
}
},
_ => 1.0 + i as Real / m.min(n).max(1) as Real,
})
} else {
z(0.0)
}
});
product(
product(q.as_ref(), d.as_ref()).as_ref(),
adjoint(v.as_ref()).as_ref(),
)
}
#[test]
fn lapack_qr_reflector_checkers() {
let packed =
Mat::from_fn(2, 1, |i, _| if i == 0 { guard() } else { phase(0) });
let coeff = Mat::full(1, 1, z(1.0));
let q = scalar_q(packed.as_ref(), coeff.as_ref());
crate::assert!(magnitude(q[(0, 0)]) < 4.0 * Real::EPSILON);
assert_eq!(q[(0, 1)], -conj(&phase(0)));
assert_eq!(q[(1, 0)], -phase(0));
crate::assert!(unitary_ratio(q.as_ref(), lin_eps()) < 30.0);
let bad = Mat::full(1, 1, z(2.0));
crate::assert!(
unitary_ratio(
scalar_q(packed.as_ref(), bad.as_ref()).as_ref(),
lin_eps()
) > 30.0
);
}