ndarray_linalg/
eig.rs

1//! Eigenvalue decomposition for non-symmetric square matrices
2
3use crate::error::*;
4use crate::layout::*;
5use crate::types::*;
6use ndarray::*;
7
8#[cfg_attr(doc, katexit::katexit)]
9/// Eigenvalue decomposition of general matrix reference
10pub trait Eig {
11    /// EigVec is the right eivenvector
12    type EigVal;
13    type EigVec;
14    /// Calculate eigenvalues with the right eigenvector
15    ///
16    /// $$ A u_i = \lambda_i u_i $$
17    ///
18    /// ```
19    /// use ndarray::*;
20    /// use ndarray_linalg::*;
21    ///
22    /// let a: Array2<f64> = array![
23    ///     [-1.01,  0.86, -4.60,  3.31, -4.81],
24    ///     [ 3.98,  0.53, -7.04,  5.29,  3.55],
25    ///     [ 3.30,  8.26, -3.89,  8.20, -1.51],
26    ///     [ 4.43,  4.96, -7.66, -7.33,  6.18],
27    ///     [ 7.31, -6.43, -6.16,  2.47,  5.58],
28    /// ];
29    /// let (eigs, vecs) = a.eig().unwrap();
30    ///
31    /// let a = a.map(|v| v.as_c());
32    /// for (&e, vec) in eigs.iter().zip(vecs.axis_iter(Axis(1))) {
33    ///     let ev = vec.map(|v| v * e);
34    ///     let av = a.dot(&vec);
35    ///     assert_close_l2!(&av, &ev, 1e-5);
36    /// }
37    /// ```
38    fn eig(&self) -> Result<(Self::EigVal, Self::EigVec)>;
39}
40
41impl<A, S> Eig for ArrayBase<S, Ix2>
42where
43    A: Scalar + Lapack,
44    S: Data<Elem = A>,
45{
46    type EigVal = Array1<A::Complex>;
47    type EigVec = Array2<A::Complex>;
48
49    fn eig(&self) -> Result<(Self::EigVal, Self::EigVec)> {
50        let mut a = self.to_owned();
51        let layout = a.square_layout()?;
52        let (s, t) = A::eig(true, layout, a.as_allocated_mut()?)?;
53        let n = layout.len() as usize;
54        Ok((
55            ArrayBase::from(s),
56            Array2::from_shape_vec((n, n).f(), t).unwrap(),
57        ))
58    }
59}
60
61/// Calculate eigenvalues without eigenvectors
62pub trait EigVals {
63    type EigVal;
64    fn eigvals(&self) -> Result<Self::EigVal>;
65}
66
67impl<A, S> EigVals for ArrayBase<S, Ix2>
68where
69    A: Scalar + Lapack,
70    S: Data<Elem = A>,
71{
72    type EigVal = Array1<A::Complex>;
73
74    fn eigvals(&self) -> Result<Self::EigVal> {
75        let mut a = self.to_owned();
76        let (s, _) = A::eig(false, a.square_layout()?, a.as_allocated_mut()?)?;
77        Ok(ArrayBase::from(s))
78    }
79}