use scirs2_core::ndarray::{Array1, Array2, ArrayView2};
use scirs2_core::numeric::{Float, One, Zero};
use super::super::{DemotableTo, PromotableTo};
use super::generalized_eigen::*;
use super::iterative::*;
use crate::error::LinalgResult;
pub type EigenResult<A> = LinalgResult<(
Array1<scirs2_core::numeric::Complex<A>>,
Array2<scirs2_core::numeric::Complex<A>>,
)>;
#[allow(dead_code)]
pub fn extended_eigvals<A, I>(
a: &ArrayView2<A>,
max_iter: Option<usize>,
tol: Option<A>,
) -> LinalgResult<Array1<scirs2_core::numeric::Complex<A>>>
where
A: Float + Zero + One + PromotableTo<I> + DemotableTo<A> + Copy,
I: Float
+ Zero
+ One
+ DemotableTo<A>
+ Copy
+ std::fmt::Debug
+ std::ops::AddAssign
+ std::ops::SubAssign
+ std::ops::DivAssign,
{
if a.nrows() != a.ncols() {
return Err(crate::error::LinalgError::ShapeError(format!(
"Expected square matrix, got shape {:?}",
a.shape()
)));
}
let n = a.nrows();
let max_iter = max_iter.unwrap_or(100 * n);
let tol = tol.unwrap_or(A::epsilon().sqrt());
let mut a_high = Array2::zeros((n, n));
for i in 0..n {
for j in 0..n {
a_high[[i, j]] = a[[i, j]].promote();
}
}
let a_high = hessenberg_reduction(a_high);
let eigenvalues_high = qr_algorithm(
a_high,
max_iter,
I::from(tol.promote()).expect("Operation failed"),
);
let mut eigenvalues = Array1::zeros(n);
for i in 0..n {
eigenvalues[i] = scirs2_core::numeric::Complex::new(
eigenvalues_high[i].re.demote(),
eigenvalues_high[i].im.demote(),
);
}
Ok(eigenvalues)
}
#[allow(dead_code)]
pub fn extended_eig<A, I>(
a: &ArrayView2<A>,
max_iter: Option<usize>,
tol: Option<A>,
) -> EigenResult<A>
where
A: Float + Zero + One + PromotableTo<I> + DemotableTo<A> + Copy,
I: Float
+ Zero
+ One
+ DemotableTo<A>
+ Copy
+ std::fmt::Debug
+ std::ops::AddAssign
+ std::ops::SubAssign
+ std::ops::DivAssign,
{
if a.nrows() != a.ncols() {
return Err(crate::error::LinalgError::ShapeError(format!(
"Expected square matrix, got shape {:?}",
a.shape()
)));
}
let eigenvalues = extended_eigvals(a, max_iter, tol)?;
let n = a.nrows();
let mut eigenvectors = Array2::zeros((n, n));
let mut a_high = Array2::zeros((n, n));
for i in 0..n {
for j in 0..n {
a_high[[i, j]] = a[[i, j]].promote();
}
}
for (k, lambda) in eigenvalues.iter().enumerate() {
let mut shiftedmatrix: Array2<scirs2_core::numeric::Complex<I>> = Array2::zeros((n, n));
let lambda_high =
scirs2_core::numeric::Complex::new(lambda.re.promote(), lambda.im.promote());
for i in 0..n {
for j in 0..n {
shiftedmatrix[[i, j]] =
scirs2_core::numeric::Complex::new(a_high[[i, j]], I::zero());
}
}
for i in 0..n {
shiftedmatrix[[i, i]] = shiftedmatrix[[i, i]] - lambda_high;
}
let eigenvector_high = compute_eigenvector_inverse_iteration(
&shiftedmatrix,
lambda_high,
max_iter.unwrap_or(100),
I::from(tol.unwrap_or(A::epsilon().sqrt()).promote()).expect("Operation failed"),
);
for i in 0..n {
eigenvectors[[i, k]] = scirs2_core::numeric::Complex::new(
eigenvector_high[i].re.demote(),
eigenvector_high[i].im.demote(),
);
}
}
Ok((eigenvalues, eigenvectors))
}
#[allow(dead_code)]
pub fn extended_eigvalsh<A, I>(
a: &ArrayView2<A>,
max_iter: Option<usize>,
tol: Option<A>,
) -> LinalgResult<Array1<A>>
where
A: Float + Zero + One + PromotableTo<I> + DemotableTo<A> + Copy,
I: Float
+ Zero
+ One
+ DemotableTo<A>
+ Copy
+ std::fmt::Debug
+ std::ops::AddAssign
+ std::ops::SubAssign
+ std::ops::DivAssign,
{
if a.nrows() != a.ncols() {
return Err(crate::error::LinalgError::ShapeError(format!(
"Expected square matrix, got shape {:?}",
a.shape()
)));
}
let n = a.nrows();
for i in 0..n {
for j in i + 1..n {
if (a[[i, j]] - a[[j, i]]).abs()
> A::epsilon() * A::from(10.0).expect("Operation failed")
{
return Err(crate::error::LinalgError::InvalidInputError(
"Matrix must be symmetric/Hermitian".to_string(),
));
}
}
}
let max_iter = max_iter.unwrap_or(100 * n);
let tol = tol.unwrap_or(A::epsilon().sqrt());
let mut a_high = Array2::zeros((n, n));
for i in 0..n {
for j in 0..n {
a_high[[i, j]] = a[[i, j]].promote();
}
}
let a_high = tridiagonalize(a_high);
let eigenvalues_high = qr_algorithm_symmetric(
a_high,
max_iter,
I::from(tol.promote()).expect("Operation failed"),
);
let mut eigenvalues = Array1::zeros(n);
for i in 0..n {
eigenvalues[i] = eigenvalues_high[i].demote();
}
Ok(eigenvalues)
}
#[allow(dead_code)]
pub fn extended_eigh<A, I>(
a: &ArrayView2<A>,
max_iter: Option<usize>,
tol: Option<A>,
) -> LinalgResult<(Array1<A>, Array2<A>)>
where
A: Float + Zero + One + PromotableTo<I> + DemotableTo<A> + Copy,
I: Float
+ Zero
+ One
+ DemotableTo<A>
+ Copy
+ std::fmt::Debug
+ std::ops::AddAssign
+ std::ops::SubAssign
+ std::ops::DivAssign
+ 'static,
{
if a.nrows() != a.ncols() {
return Err(crate::error::LinalgError::ShapeError(format!(
"Expected square matrix, got shape {:?}",
a.shape()
)));
}
let n = a.nrows();
for i in 0..n {
for j in i + 1..n {
if (a[[i, j]] - a[[j, i]]).abs()
> A::epsilon() * A::from(10.0).expect("Operation failed")
{
return Err(crate::error::LinalgError::InvalidInputError(
"Matrix must be symmetric/Hermitian".to_string(),
));
}
}
}
let max_iter = max_iter.unwrap_or(100 * n);
let tol = tol.unwrap_or(A::epsilon().sqrt());
let mut a_high = Array2::zeros((n, n));
for i in 0..n {
for j in 0..n {
a_high[[i, j]] = a[[i, j]].promote();
}
}
let (a_tri, q) = tridiagonalize_with_transform(a_high);
let (eigenvalues_high, eigenvectors_high) = qr_algorithm_symmetric_with_vectors(
a_tri,
q,
max_iter,
I::from(tol.promote()).expect("Operation failed"),
);
let mut eigenvalues = Array1::zeros(n);
let mut eigenvectors = Array2::zeros((n, n));
for i in 0..n {
eigenvalues[i] = eigenvalues_high[i].demote();
for j in 0..n {
eigenvectors[[i, j]] = eigenvectors_high[[i, j]].demote();
}
}
Ok((eigenvalues, eigenvectors))
}