use num_complex::Complex64;
pub(crate) fn det_complex(
n: usize,
entries: &[(usize, usize)],
re: &[f64],
im: &[f64],
) -> (Complex64, i32) {
if n == 0 {
return (Complex64::new(1.0, 0.0), 0);
}
let mut a = vec![Complex64::new(0.0, 0.0); n * n];
for (k, (r, c)) in entries.iter().enumerate() {
a[r * n + c] += Complex64::new(re[k], im[k]);
}
let mut det = Complex64::new(1.0, 0.0);
let mut exp = 0i32;
let mut sign = 1.0f64;
for col in 0..n {
let mut piv = col;
let mut best = a[col * n + col].re.abs() + a[col * n + col].im.abs();
for r in col + 1..n {
let m = a[r * n + col].re.abs() + a[r * n + col].im.abs();
if m > best {
best = m;
piv = r;
}
}
if best == 0.0 {
return (Complex64::new(0.0, 0.0), 0);
}
if piv != col {
for c in 0..n {
a.swap(piv * n + c, col * n + c);
}
sign = -sign;
}
let p = a[col * n + col];
det *= p;
if det.re == 0.0 && det.im == 0.0 {
return (Complex64::new(0.0, 0.0), 0);
}
while det.re.abs() > 1.0 || det.im.abs() > 1.0 {
exp += 1;
det.re /= 2.0;
det.im /= 2.0;
}
while det.re.abs() <= 0.5 && det.im.abs() <= 0.5 {
exp -= 1;
det.re *= 2.0;
det.im *= 2.0;
}
for r in col + 1..n {
let f = a[r * n + col] / p;
if f.re == 0.0 && f.im == 0.0 {
continue;
}
for c in col + 1..n {
let v = a[col * n + c];
a[r * n + c] -= f * v;
}
}
}
if !det.re.is_finite() || !det.im.is_finite() {
return (Complex64::new(0.0, 0.0), 0);
}
(det * sign, exp)
}