nalgebra-lapack: add computation of complex eigenvalues.
Also renames RealEigensystem -> Eigen
This commit is contained in:
parent
c616c3ddef
commit
89e8b49759
|
@ -1,4 +1,5 @@
|
||||||
use num::Zero;
|
use num::Zero;
|
||||||
|
use num_complex::Complex;
|
||||||
|
|
||||||
use alga::general::Real;
|
use alga::general::Real;
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ use na::allocator::Allocator;
|
||||||
use lapack::fortran as interface;
|
use lapack::fortran as interface;
|
||||||
|
|
||||||
/// Eigendecomposition of a real square matrix with real eigenvalues.
|
/// Eigendecomposition of a real square matrix with real eigenvalues.
|
||||||
pub struct RealEigensystem<N: Scalar, D: Dim>
|
pub struct Eigen<N: Scalar, D: Dim>
|
||||||
where DefaultAllocator: Allocator<N, D> +
|
where DefaultAllocator: Allocator<N, D> +
|
||||||
Allocator<N, D, D> {
|
Allocator<N, D, D> {
|
||||||
pub eigenvalues: VectorN<N, D>,
|
pub eigenvalues: VectorN<N, D>,
|
||||||
|
@ -20,14 +21,14 @@ pub struct RealEigensystem<N: Scalar, D: Dim>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<N: RealEigensystemScalar + Real, D: Dim> RealEigensystem<N, D>
|
impl<N: EigenScalar + Real, D: Dim> Eigen<N, D>
|
||||||
where DefaultAllocator: Allocator<N, D, D> +
|
where DefaultAllocator: Allocator<N, D, D> +
|
||||||
Allocator<N, D> {
|
Allocator<N, D> {
|
||||||
/// Computes the eigenvalues and eigenvectors of the square matrix `m`.
|
/// Computes the eigenvalues and eigenvectors of the square matrix `m`.
|
||||||
///
|
///
|
||||||
/// If `eigenvectors` is `false` then, the eigenvectors are not computed explicitly.
|
/// If `eigenvectors` is `false` then, the eigenvectors are not computed explicitly.
|
||||||
pub fn new(mut m: MatrixN<N, D>, left_eigenvectors: bool, eigenvectors: bool)
|
pub fn new(mut m: MatrixN<N, D>, left_eigenvectors: bool, eigenvectors: bool)
|
||||||
-> Option<RealEigensystem<N, D>> {
|
-> Option<Eigen<N, D>> {
|
||||||
|
|
||||||
assert!(m.is_square(), "Unable to compute the eigenvalue decomposition of a non-square matrix.");
|
assert!(m.is_square(), "Unable to compute the eigenvalue decomposition of a non-square matrix.");
|
||||||
|
|
||||||
|
@ -67,7 +68,7 @@ impl<N: RealEigensystemScalar + Real, D: Dim> RealEigensystem<N, D>
|
||||||
lapack_check!(info);
|
lapack_check!(info);
|
||||||
|
|
||||||
if wi.iter().all(|e| e.is_zero()) {
|
if wi.iter().all(|e| e.is_zero()) {
|
||||||
return Some(RealEigensystem {
|
return Some(Eigen {
|
||||||
eigenvalues: wr, left_eigenvectors: Some(vl), eigenvectors: Some(vr)
|
eigenvalues: wr, left_eigenvectors: Some(vl), eigenvectors: Some(vr)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -81,7 +82,7 @@ impl<N: RealEigensystemScalar + Real, D: Dim> RealEigensystem<N, D>
|
||||||
lapack_check!(info);
|
lapack_check!(info);
|
||||||
|
|
||||||
if wi.iter().all(|e| e.is_zero()) {
|
if wi.iter().all(|e| e.is_zero()) {
|
||||||
return Some(RealEigensystem {
|
return Some(Eigen {
|
||||||
eigenvalues: wr, left_eigenvectors: Some(vl), eigenvectors: None
|
eigenvalues: wr, left_eigenvectors: Some(vl), eigenvectors: None
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -95,7 +96,7 @@ impl<N: RealEigensystemScalar + Real, D: Dim> RealEigensystem<N, D>
|
||||||
lapack_check!(info);
|
lapack_check!(info);
|
||||||
|
|
||||||
if wi.iter().all(|e| e.is_zero()) {
|
if wi.iter().all(|e| e.is_zero()) {
|
||||||
return Some(RealEigensystem {
|
return Some(Eigen {
|
||||||
eigenvalues: wr, left_eigenvectors: None, eigenvectors: Some(vr)
|
eigenvalues: wr, left_eigenvectors: None, eigenvectors: Some(vr)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -107,7 +108,7 @@ impl<N: RealEigensystemScalar + Real, D: Dim> RealEigensystem<N, D>
|
||||||
lapack_check!(info);
|
lapack_check!(info);
|
||||||
|
|
||||||
if wi.iter().all(|e| e.is_zero()) {
|
if wi.iter().all(|e| e.is_zero()) {
|
||||||
return Some(RealEigensystem {
|
return Some(Eigen {
|
||||||
eigenvalues: wr, left_eigenvectors: None, eigenvectors: None
|
eigenvalues: wr, left_eigenvectors: None, eigenvectors: None
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -117,6 +118,48 @@ impl<N: RealEigensystemScalar + Real, D: Dim> RealEigensystem<N, D>
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The complex eigenvalues of the given matrix.
|
||||||
|
///
|
||||||
|
/// Panics if the eigenvalue computation does not converge.
|
||||||
|
pub fn complex_eigenvalues(mut m: MatrixN<N, D>) -> VectorN<Complex<N>, D>
|
||||||
|
where DefaultAllocator: Allocator<Complex<N>, D> {
|
||||||
|
assert!(m.is_square(), "Unable to compute the eigenvalue decomposition of a non-square matrix.");
|
||||||
|
|
||||||
|
let (nrows, ncols) = m.data.shape();
|
||||||
|
let n = nrows.value();
|
||||||
|
|
||||||
|
let lda = n as i32;
|
||||||
|
|
||||||
|
let mut wr = unsafe { Matrix::new_uninitialized_generic(nrows, U1) };
|
||||||
|
let mut wi = unsafe { Matrix::new_uninitialized_generic(nrows, U1) };
|
||||||
|
|
||||||
|
|
||||||
|
let mut info = 0;
|
||||||
|
let mut placeholder1 = [ N::zero() ];
|
||||||
|
let mut placeholder2 = [ N::zero() ];
|
||||||
|
|
||||||
|
let lwork = N::xgeev_work_size(b'N', b'N', n as i32, m.as_mut_slice(), lda,
|
||||||
|
wr.as_mut_slice(), wi.as_mut_slice(), &mut placeholder1,
|
||||||
|
n as i32, &mut placeholder2, n as i32, &mut info);
|
||||||
|
|
||||||
|
lapack_panic!(info);
|
||||||
|
|
||||||
|
let mut work = unsafe { ::uninitialized_vec(lwork as usize) };
|
||||||
|
|
||||||
|
N::xgeev(b'N', b'N', n as i32, m.as_mut_slice(), lda, wr.as_mut_slice(),
|
||||||
|
wi.as_mut_slice(), &mut placeholder1, 1 as i32, &mut placeholder2,
|
||||||
|
1 as i32, &mut work, lwork, &mut info);
|
||||||
|
lapack_panic!(info);
|
||||||
|
|
||||||
|
let mut res = unsafe { Matrix::new_uninitialized_generic(nrows, U1) };
|
||||||
|
|
||||||
|
for i in 0 .. res.len() {
|
||||||
|
res[i] = Complex::new(wr[i], wi[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
/// The determinant of the decomposed matrix.
|
/// The determinant of the decomposed matrix.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn determinant(&self) -> N {
|
pub fn determinant(&self) -> N {
|
||||||
|
@ -138,7 +181,7 @@ impl<N: RealEigensystemScalar + Real, D: Dim> RealEigensystem<N, D>
|
||||||
* Lapack functions dispatch.
|
* Lapack functions dispatch.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
pub trait RealEigensystemScalar: Scalar {
|
pub trait EigenScalar: Scalar {
|
||||||
fn xgeev(jobvl: u8, jobvr: u8, n: i32, a: &mut [Self], lda: i32,
|
fn xgeev(jobvl: u8, jobvr: u8, n: i32, a: &mut [Self], lda: i32,
|
||||||
wr: &mut [Self], wi: &mut [Self],
|
wr: &mut [Self], wi: &mut [Self],
|
||||||
vl: &mut [Self], ldvl: i32, vr: &mut [Self], ldvr: i32,
|
vl: &mut [Self], ldvl: i32, vr: &mut [Self], ldvr: i32,
|
||||||
|
@ -150,7 +193,7 @@ pub trait RealEigensystemScalar: Scalar {
|
||||||
|
|
||||||
macro_rules! real_eigensystem_scalar_impl (
|
macro_rules! real_eigensystem_scalar_impl (
|
||||||
($N: ty, $xgeev: path) => (
|
($N: ty, $xgeev: path) => (
|
||||||
impl RealEigensystemScalar for $N {
|
impl EigenScalar for $N {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn xgeev(jobvl: u8, jobvr: u8, n: i32, a: &mut [Self], lda: i32,
|
fn xgeev(jobvl: u8, jobvr: u8, n: i32, a: &mut [Self], lda: i32,
|
||||||
wr: &mut [Self], wi: &mut [Self],
|
wr: &mut [Self], wi: &mut [Self],
|
||||||
|
|
|
@ -11,7 +11,7 @@ use na::allocator::Allocator;
|
||||||
|
|
||||||
use lapack::fortran as interface;
|
use lapack::fortran as interface;
|
||||||
|
|
||||||
/// Eigendecomposition of a real square matrix with real eigenvalues.
|
/// SymmetricEigendecomposition of a real square matrix with real eigenvalues.
|
||||||
pub struct SymmetricEigen<N: Scalar, D: Dim>
|
pub struct SymmetricEigen<N: Scalar, D: Dim>
|
||||||
where DefaultAllocator: Allocator<N, D> +
|
where DefaultAllocator: Allocator<N, D> +
|
||||||
Allocator<N, D, D> {
|
Allocator<N, D, D> {
|
||||||
|
@ -20,7 +20,7 @@ pub struct SymmetricEigen<N: Scalar, D: Dim>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<N: RealEigensystemScalar + Real, D: Dim> SymmetricEigen<N, D>
|
impl<N: SymmetricEigenScalar + Real, D: Dim> SymmetricEigen<N, D>
|
||||||
where DefaultAllocator: Allocator<N, D, D> +
|
where DefaultAllocator: Allocator<N, D, D> +
|
||||||
Allocator<N, D> {
|
Allocator<N, D> {
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ impl<N: RealEigensystemScalar + Real, D: Dim> SymmetricEigen<N, D>
|
||||||
* Lapack functions dispatch.
|
* Lapack functions dispatch.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
pub trait RealEigensystemScalar: Scalar {
|
pub trait SymmetricEigenScalar: Scalar {
|
||||||
fn xsyev(jobz: u8, uplo: u8, n: i32, a: &mut [Self], lda: i32, w: &mut [Self], work: &mut [Self],
|
fn xsyev(jobz: u8, uplo: u8, n: i32, a: &mut [Self], lda: i32, w: &mut [Self], work: &mut [Self],
|
||||||
lwork: i32, info: &mut i32);
|
lwork: i32, info: &mut i32);
|
||||||
fn xsyev_work_size(jobz: u8, uplo: u8, n: i32, a: &mut [Self], lda: i32, info: &mut i32) -> i32;
|
fn xsyev_work_size(jobz: u8, uplo: u8, n: i32, a: &mut [Self], lda: i32, info: &mut i32) -> i32;
|
||||||
|
@ -121,7 +121,7 @@ pub trait RealEigensystemScalar: Scalar {
|
||||||
|
|
||||||
macro_rules! real_eigensystem_scalar_impl (
|
macro_rules! real_eigensystem_scalar_impl (
|
||||||
($N: ty, $xsyev: path) => (
|
($N: ty, $xsyev: path) => (
|
||||||
impl RealEigensystemScalar for $N {
|
impl SymmetricEigenScalar for $N {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn xsyev(jobz: u8, uplo: u8, n: i32, a: &mut [Self], lda: i32, w: &mut [Self], work: &mut [Self],
|
fn xsyev(jobz: u8, uplo: u8, n: i32, a: &mut [Self], lda: i32, w: &mut [Self], work: &mut [Self],
|
||||||
lwork: i32, info: &mut i32) {
|
lwork: i32, info: &mut i32) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
||||||
use nl::RealEigensystem;
|
use nl::Eigen;
|
||||||
use na::{DMatrix, Matrix4};
|
use na::{DMatrix, Matrix4};
|
||||||
|
|
||||||
quickcheck!{
|
quickcheck!{
|
||||||
|
@ -9,7 +9,7 @@ quickcheck!{
|
||||||
let n = cmp::min(n, 25);
|
let n = cmp::min(n, 25);
|
||||||
let m = DMatrix::<f64>::new_random(n, n);
|
let m = DMatrix::<f64>::new_random(n, n);
|
||||||
|
|
||||||
match RealEigensystem::new(m.clone(), true, true) {
|
match Eigen::new(m.clone(), true, true) {
|
||||||
Some(eig) => {
|
Some(eig) => {
|
||||||
let eigvals = DMatrix::from_diagonal(&eig.eigenvalues);
|
let eigvals = DMatrix::from_diagonal(&eig.eigenvalues);
|
||||||
let transformed_eigvectors = &m * eig.eigenvectors.as_ref().unwrap();
|
let transformed_eigvectors = &m * eig.eigenvectors.as_ref().unwrap();
|
||||||
|
@ -30,7 +30,7 @@ quickcheck!{
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eigensystem_static(m: Matrix4<f64>) -> bool {
|
fn eigensystem_static(m: Matrix4<f64>) -> bool {
|
||||||
match RealEigensystem::new(m, true, true) {
|
match Eigen::new(m, true, true) {
|
||||||
Some(eig) => {
|
Some(eig) => {
|
||||||
let eigvals = Matrix4::from_diagonal(&eig.eigenvalues);
|
let eigvals = Matrix4::from_diagonal(&eig.eigenvalues);
|
||||||
let transformed_eigvectors = m * eig.eigenvectors.unwrap();
|
let transformed_eigvectors = m * eig.eigenvectors.unwrap();
|
||||||
|
|
Loading…
Reference in New Issue