use faer::sparse::SparseColMatRef;
use faer::sparse::linalg::matmul::sparse_dense_matmul;
use faer::{Accum, Mat, MatMut, MatRef, Par};
use faer_traits::math_utils::{abs, add, conj, from_f64, mul, mul_real, one, real, recip, sqrt, sub, zero};
use faer_traits::{ComplexField, Index};
pub(crate) fn gershgorin_bounds<I: Index, T: ComplexField>(
a: SparseColMatRef<'_, I, T>,
) -> (T::Real, T::Real) {
let n = a.nrows();
let mut diag = vec![zero::<T::Real>(); n];
let mut radius = vec![zero::<T::Real>(); n];
for j in 0..n {
let rows = a.symbolic().row_idx_of_col_raw(j);
let vals = a.val_of_col(j);
for (raw, v) in rows.iter().zip(vals.iter()) {
let i = raw.zx();
if i == j {
diag[i] = real(v);
} else {
radius[i] = add(&radius[i], &abs(v));
}
}
}
if n == 0 {
return (zero::<T::Real>(), zero::<T::Real>());
}
let mut lo = sub(&diag[0], &radius[0]);
let mut hi = add(&diag[0], &radius[0]);
for i in 1..n {
let disc_lo = sub(&diag[i], &radius[i]);
let disc_hi = add(&diag[i], &radius[i]);
if disc_lo < lo {
lo = disc_lo;
}
if disc_hi > hi {
hi = disc_hi;
}
}
(lo, hi)
}
pub(crate) fn power_iteration_max<I: Index, T: ComplexField>(
a: SparseColMatRef<'_, I, T>,
iters: usize,
) -> T::Real {
let n = a.nrows();
if n == 0 {
return zero::<T::Real>();
}
let mut x = Mat::<T>::from_fn(n, 1, |i, _| from_f64::<T>(1.0 + (i % 7) as f64 * 0.5));
normalize(x.as_mut());
let mut y = Mat::<T>::zeros(n, 1);
let mut lambda = zero::<T::Real>();
for _ in 0..iters {
sparse_dense_matmul(y.as_mut(), Accum::Replace, a, x.as_ref(), one::<T>(), Par::Seq);
lambda = real_dot(x.as_ref(), y.as_ref());
let nrm = sqrt::<T::Real>(&real_dot(y.as_ref(), y.as_ref()));
if nrm == zero::<T::Real>() {
break;
}
let inv = recip(&nrm);
for i in 0..n {
let scaled = mul_real(y.as_ref().get(i, 0), &inv);
*x.as_mut().get_mut(i, 0) = scaled;
}
}
abs(&lambda)
}
fn real_dot<T: ComplexField>(x: MatRef<'_, T>, y: MatRef<'_, T>) -> T::Real {
let mut acc = zero::<T::Real>();
for i in 0..x.nrows() {
acc = add(&acc, &real(&mul(&conj(x.get(i, 0)), y.get(i, 0))));
}
acc
}
fn normalize<T: ComplexField>(mut x: MatMut<'_, T>) {
let nrm = sqrt::<T::Real>(&real_dot(x.as_ref(), x.as_ref()));
if nrm == zero::<T::Real>() {
return;
}
let inv = recip(&nrm);
for i in 0..x.nrows() {
let scaled = mul_real(x.as_ref().get(i, 0), &inv);
*x.as_mut().get_mut(i, 0) = scaled;
}
}