use super::SymmetricEigen;
use crate::{Backend, Matrix, TruenoError, Vector};
impl SymmetricEigen {
pub fn eigenvalues(&self) -> &[f32] {
&self.eigenvalues
}
pub fn eigenvectors(&self) -> &Matrix<f32> {
&self.eigenvectors
}
pub fn iter(&self) -> EigenIterator<'_> {
EigenIterator { eigen: self, index: 0 }
}
pub fn len(&self) -> usize {
self.eigenvalues.len()
}
pub fn is_empty(&self) -> bool {
self.eigenvalues.is_empty()
}
pub fn backend(&self) -> Backend {
self.backend
}
pub fn eigenvector(&self, i: usize) -> Option<Vector<f32>> {
contract_pre_eigenvector!();
if i >= self.eigenvalues.len() {
return None;
}
let n = self.eigenvectors.rows();
let mut data = Vec::with_capacity(n);
for row in 0..n {
if let Some(&val) = self.eigenvectors.get(row, i) {
data.push(val);
}
}
Some(Vector::from_slice(&data))
}
pub fn reconstruct(&self) -> Result<Matrix<f32>, TruenoError> {
let n = self.eigenvalues.len();
let mut vd_data = vec![0.0f32; n * n];
for i in 0..n {
let lambda = self.eigenvalues[i];
for j in 0..n {
if let Some(&v) = self.eigenvectors.get(j, i) {
vd_data[j * n + i] = v * lambda;
}
}
}
let vd = Matrix::from_vec(n, n, vd_data)?;
let vt = self.eigenvectors.transpose();
vd.matmul(&vt)
}
}
pub struct EigenIterator<'a> {
pub(super) eigen: &'a SymmetricEigen,
pub(super) index: usize,
}
impl<'a> Iterator for EigenIterator<'a> {
type Item = (f32, Vector<f32>);
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.eigen.len() {
return None;
}
let value = self.eigen.eigenvalues[self.index];
let vector = self.eigen.eigenvector(self.index)?;
self.index += 1;
Some((value, vector))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.eigen.len() - self.index;
(remaining, Some(remaining))
}
}
impl<'a> ExactSizeIterator for EigenIterator<'a> {}