use scirs2_core::ndarray::{Array1, Array2, ArrayView2};
use scirs2_core::numeric::{Float, NumAssign, One, Zero};
use std::iter::Sum;
use crate::error::{LinalgError, LinalgResult};
use crate::specialized::BandedMatrix;
#[allow(dead_code)]
pub fn banded_eigh<F>(a: &ArrayView2<F>, bandwidth: usize) -> LinalgResult<(Array1<F>, Array2<F>)>
where
F: Float
+ NumAssign
+ Sum
+ One
+ Zero
+ 'static
+ scirs2_core::ndarray::ScalarOperand
+ Send
+ Sync
+ std::fmt::Debug,
{
let n = a.nrows();
if a.ncols() != n {
return Err(LinalgError::ShapeError(format!(
"Expected square matrix, got shape {:?}",
a.shape()
)));
}
for i in 0..n {
for j in i + 1..std::cmp::min(i + bandwidth + 1, n) {
let diff = (a[[i, j]] - a[[j, i]]).abs();
if diff > F::epsilon() * F::from(10.0).expect("Operation failed") {
return Err(LinalgError::ShapeError(
"Matrix must be symmetric for banded_eigh function".to_string(),
));
}
}
}
let _banded = BandedMatrix::frommatrix(a, bandwidth, bandwidth)?;
if bandwidth == 1 {
let diag = Array1::from_iter((0..n).map(|i| a[[i, i]]));
let subdiag = Array1::from_iter((0..n - 1).map(|i| a[[i + 1, i]]));
return crate::eigen_specialized::tridiagonal::tridiagonal_eigh(
&diag.view(),
&subdiag.view(),
);
}
let mut diag = Array1::zeros(n);
let mut subdiag = Array1::zeros(n - 1);
let mut q = Array2::eye(n);
for i in 0..n {
diag[i] = a[[i, i]];
}
let mut h = a.to_owned();
for i in 0..n - 2 {
for j in (i + 2)..std::cmp::min(i + bandwidth + 1, n) {
if h[[j, i]].abs() > F::epsilon() {
let x = h[[j - 1, i]];
let y = h[[j, i]];
let r = (x * x + y * y).sqrt();
let c = x / r;
let s = -y / r;
for k in i..std::cmp::min(j + bandwidth + 1, n) {
let temp = h[[j - 1, k]];
h[[j - 1, k]] = c * temp - s * h[[j, k]];
h[[j, k]] = s * temp + c * h[[j, k]];
}
for k in std::cmp::max(0, j - bandwidth - 1)..j + 1 {
let temp = h[[k, j - 1]];
h[[k, j - 1]] = c * temp - s * h[[k, j]];
h[[k, j]] = s * temp + c * h[[k, j]];
}
for k in 0..n {
let temp = q[[k, j - 1]];
q[[k, j - 1]] = c * temp - s * q[[k, j]];
q[[k, j]] = s * temp + c * q[[k, j]];
}
}
}
}
for i in 0..n {
diag[i] = h[[i, i]];
if i < n - 1 {
subdiag[i] = h[[i + 1, i]];
}
}
let (eigenvalues, tri_vectors) =
crate::eigen_specialized::tridiagonal::tridiagonal_eigh(&diag.view(), &subdiag.view())?;
let eigenvectors = q.dot(&tri_vectors);
Ok((eigenvalues, eigenvectors))
}
#[allow(dead_code)]
pub fn banded_eigvalsh<F>(a: &ArrayView2<F>, bandwidth: usize) -> LinalgResult<Array1<F>>
where
F: Float
+ NumAssign
+ Sum
+ One
+ Zero
+ 'static
+ scirs2_core::ndarray::ScalarOperand
+ Send
+ Sync
+ std::fmt::Debug,
{
let n = a.nrows();
if bandwidth == 1 {
let diag = Array1::from_iter((0..n).map(|i| a[[i, i]]));
let subdiag = Array1::from_iter((0..n - 1).map(|i| a[[i + 1, i]]));
return crate::eigen_specialized::tridiagonal::tridiagonal_eigvalsh(
&diag.view(),
&subdiag.view(),
);
}
let (eigenvalues_) = banded_eigh(a, bandwidth)?;
Ok(eigenvalues)
}