Function russell_lab::matrix::mat_eigen
source · pub fn mat_eigen(
l_real: &mut Vector,
l_imag: &mut Vector,
v_real: &mut Matrix,
v_imag: &mut Matrix,
a: &mut Matrix
) -> Result<(), StrError>
Expand description
(dgeev) Performs the eigen-decomposition of a square matrix
Computes the eigenvalues l
and right eigenvectors v
, such that:
a ⋅ vj = lj ⋅ vj
where lj
is the component j of l
and vj
is the column j of v
.
See also: https://www.netlib.org/lapack/explore-html/d9/d28/dgeev_8f.html
§Output
l_real
– (m) eigenvalues; real partl_imag
– (m) eigenvalues; imaginary partv_real
– (m,m) right eigenvectors (as columns); real partv_imag
– (m,m) right eigenvectors (as columns); imaginary part
§Input
a
– (m,m) general matrix (will be modified)
§Note
- The matrix
a
will be modified
§Similarity transformation
The eigen-decomposition leads to a similarity transformation like so:
a = v⋅λ⋅v⁻¹
where v
is a matrix whose columns are the m linearly independent eigenvectors of a
,
and λ
is a matrix whose diagonal are the eigenvalues of a
. Thus, the following is valid:
a⋅v = v⋅λ
Let us define the error err
as follows:
err := a⋅v - v⋅λ
§Examples
use russell_lab::*;
fn main() -> Result<(), StrError> {
// set matrix
let data = [[2.0, 0.0, 0.0], [0.0, 3.0, 4.0], [0.0, 4.0, 9.0]];
let mut a = Matrix::from(&data);
// allocate output arrays
let m = a.nrow();
let mut l_real = Vector::new(m);
let mut l_imag = Vector::new(m);
let mut v_real = Matrix::new(m, m);
let mut v_imag = Matrix::new(m, m);
// perform the eigen-decomposition
mat_eigen(&mut l_real, &mut l_imag, &mut v_real, &mut v_imag, &mut a)?;
// check results
assert_eq!(
format!("{:.1}", l_real),
"┌ ┐\n\
│ 11.0 │\n\
│ 1.0 │\n\
│ 2.0 │\n\
└ ┘"
);
assert_eq!(
format!("{}", l_imag),
"┌ ┐\n\
│ 0 │\n\
│ 0 │\n\
│ 0 │\n\
└ ┘"
);
// check eigen-decomposition (similarity transformation) of a
// symmetric matrix with real-only eigenvalues and eigenvectors
let a_copy = Matrix::from(&data);
let lam = Matrix::diagonal(l_real.as_data());
let mut a_v = Matrix::new(m, m);
let mut v_l = Matrix::new(m, m);
let mut err = Matrix::filled(m, m, f64::MAX);
mat_mat_mul(&mut a_v, 1.0, &a_copy, &v_real, 0.0)?;
mat_mat_mul(&mut v_l, 1.0, &v_real, &lam, 0.0)?;
mat_add(&mut err, 1.0, &a_v, -1.0, &v_l)?;
approx_eq(mat_norm(&err, Norm::Max), 0.0, 1e-15);
Ok(())
}