Skip to content

Commit 8e1191d

Browse files
committed
add eig
1 parent cdc6db1 commit 8e1191d

File tree

5 files changed

+135
-1
lines changed

5 files changed

+135
-1
lines changed

examples/eig.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
extern crate ndarray;
2+
extern crate ndarray_linalg;
3+
4+
use ndarray::*;
5+
use ndarray_linalg::*;
6+
7+
fn main() {
8+
let a = arr2(&[[0.0, -1.0, 0.0], [-1.0, 0.0, 0.0], [0.0, 3.0, 2.0]]);
9+
let (e, vecs) = a.clone().eig().unwrap();
10+
println!("eigenvalues = \n{:?}", e);
11+
println!("V = \n{:?}", vecs.t());
12+
let av = a.dot(&vecs.t());
13+
println!("AV = \n{:?}", av);
14+
}

src/eig.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//! Eigenvalue decomposition for Hermite matrices
2+
3+
use ndarray::*;
4+
use crate::error::*;
5+
use crate::layout::*;
6+
use crate::types::*;
7+
8+
/// Eigenvalue decomposition of general matrix reference
9+
pub trait Eig {
10+
type EigVal;
11+
type EigVec;
12+
fn eig(&self) -> Result<(Self::EigVal, Self::EigVec)>;
13+
}
14+
15+
impl<A, S> Eig for ArrayBase<S, Ix2>
16+
where
17+
A: Scalar + Lapack,
18+
S: Data<Elem = A>,
19+
{
20+
type EigVal = Array1<A::Complex>;
21+
type EigVec = Array2<A>;
22+
23+
fn eig(&self) -> Result<(Self::EigVal, Self::EigVec)> {
24+
let mut a = self.to_owned();
25+
let layout = a.square_layout()?;
26+
// XXX Force layout to be Fortran (see #146)
27+
match layout {
28+
MatrixLayout::C(_) => a.swap_axes(0, 1),
29+
MatrixLayout::F(_) => {}
30+
}
31+
let (s, t) = unsafe { A::eig(true, a.square_layout()?, a.as_allocated_mut()?)? };
32+
let (n, _) = layout.size();
33+
println!("{:?}", t);
34+
Ok((ArrayBase::from(s), ArrayBase::from(t).into_shape((n as usize, n as usize)).unwrap()))
35+
}
36+
}
37+
38+
/// Calculate eigenvalues without eigenvectors
39+
pub trait EigVals {
40+
type EigVal;
41+
fn eigvals(&self) -> Result<Self::EigVal>;
42+
}
43+
44+
impl<A, S> EigVals for ArrayBase<S, Ix2>
45+
where
46+
A: Scalar + Lapack,
47+
S: DataMut<Elem = A>,
48+
{
49+
type EigVal = Array1<A::Complex>;
50+
51+
fn eigvals(&self) -> Result<Self::EigVal> {
52+
let mut a = self.to_owned();
53+
let layout = a.square_layout()?;
54+
// XXX Force layout to be Fortran (see #146)
55+
match layout {
56+
MatrixLayout::C(_) => a.swap_axes(0, 1),
57+
MatrixLayout::F(_) => {}
58+
}
59+
let (s, _) = unsafe { A::eig(true, a.square_layout()?, a.as_allocated_mut()?)? };
60+
Ok(ArrayBase::from(s))
61+
}
62+
}

src/lapack/eig.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//! Eigenvalue decomposition for general matrices
2+
3+
use lapacke;
4+
use num_traits::Zero;
5+
6+
use crate::error::*;
7+
use crate::layout::MatrixLayout;
8+
use crate::types::*;
9+
10+
use super::into_result;
11+
12+
/// Wraps `*geev` for real/complex
13+
pub trait Eig_: Scalar {
14+
unsafe fn eig(calc_v: bool, l: MatrixLayout, a: &mut [Self]) -> Result<(Vec<Self::Complex>, Vec<Self>)>;
15+
}
16+
17+
macro_rules! impl_eig_complex {
18+
($scalar:ty, $ev:path) => {
19+
impl Eig_ for $scalar {
20+
unsafe fn eig(calc_v: bool, l: MatrixLayout, mut a: &mut [Self]) -> Result<(Vec<Self::Complex>, Vec<Self::Complex>)> {
21+
let (n, _) = l.size();
22+
let jobvl = if calc_v { b'V' } else { b'N' };
23+
let mut w = vec![Self::Complex::zero(); n as usize];
24+
let mut vl = vec![Self::Complex::zero(); (n * n) as usize];
25+
let mut vr = Vec::new();
26+
let info = $ev(l.lapacke_layout(), jobvl, b'N', n, &mut a, n, &mut w, &mut vl, n, &mut vr, n);
27+
into_result(info, (w, vl))
28+
}
29+
}
30+
};
31+
}
32+
33+
macro_rules! impl_eig_real {
34+
($scalar:ty, $ev:path, $cn:ty) => {
35+
impl Eig_ for $scalar {
36+
unsafe fn eig(calc_v: bool, l: MatrixLayout, mut a: &mut [Self]) -> Result<(Vec<Self::Complex>, Vec<Self::Real>)> {
37+
let (n, _) = l.size();
38+
let jobvl = if calc_v { b'V' } else { b'N' };
39+
let mut wr = vec![Self::Real::zero(); n as usize];
40+
let mut wi = vec![Self::Real::zero(); n as usize];
41+
let mut vl = vec![Self::Real::zero(); (n * n) as usize];
42+
let mut vr = Vec::new();
43+
let info = $ev(l.lapacke_layout(), jobvl, b'N', n, &mut a, n, &mut wr, &mut wi, &mut vl, n, &mut vr, n);
44+
let w: Vec<$cn> = wr.iter().zip(wi.iter()).map(|(&r, &i)| <$cn>::new(r, i)).collect();
45+
into_result(info, (w, vl))
46+
}
47+
}
48+
};
49+
}
50+
51+
impl_eig_real!(f64, lapacke::dgeev, c64);
52+
impl_eig_real!(f32, lapacke::sgeev, c32);
53+
impl_eig_complex!(c64, lapacke::zgeev);
54+
impl_eig_complex!(c32, lapacke::cgeev);

src/lapack/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Define traits wrapping LAPACK routines
22
33
pub mod cholesky;
4+
pub mod eig;
45
pub mod eigh;
56
pub mod opnorm;
67
pub mod qr;
@@ -11,6 +12,7 @@ pub mod svddc;
1112
pub mod triangular;
1213

1314
pub use self::cholesky::*;
15+
pub use self::eig::*;
1416
pub use self::eigh::*;
1517
pub use self::opnorm::*;
1618
pub use self::qr::*;
@@ -26,7 +28,7 @@ use super::types::*;
2628
pub type Pivot = Vec<i32>;
2729

2830
/// Trait for primitive types which implements LAPACK subroutines
29-
pub trait Lapack: OperatorNorm_ + QR_ + SVD_ + SVDDC_ + Solve_ + Solveh_ + Cholesky_ + Eigh_ + Triangular_ {}
31+
pub trait Lapack: OperatorNorm_ + QR_ + SVD_ + SVDDC_ + Solve_ + Solveh_ + Cholesky_ + Eig_ + Eigh_ + Triangular_ {}
3032

3133
impl Lapack for f32 {}
3234
impl Lapack for f64 {}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub mod assert;
4343
pub mod cholesky;
4444
pub mod convert;
4545
pub mod diagonal;
46+
pub mod eig;
4647
pub mod eigh;
4748
pub mod error;
4849
pub mod generate;
@@ -66,6 +67,7 @@ pub use assert::*;
6667
pub use cholesky::*;
6768
pub use convert::*;
6869
pub use diagonal::*;
70+
pub use eig::*;
6971
pub use eigh::*;
7072
pub use generate::*;
7173
pub use inner::*;

0 commit comments

Comments
 (0)