2
2
3
3
use crate :: { error:: * , layout:: MatrixLayout } ;
4
4
use cauchy:: * ;
5
- use num_traits:: Zero ;
5
+ use num_traits:: { ToPrimitive , Zero } ;
6
6
7
- /// Wraps `*geev` for real/complex
7
+ /// Wraps `*geev` for general matrices
8
8
pub trait Eig_ : Scalar {
9
- unsafe fn eig (
9
+ /// Calculate Right eigenvalue
10
+ fn eig (
10
11
calc_v : bool ,
11
12
l : MatrixLayout ,
12
13
a : & mut [ Self ] ,
@@ -16,65 +17,159 @@ pub trait Eig_: Scalar {
16
17
macro_rules! impl_eig_complex {
17
18
( $scalar: ty, $ev: path) => {
18
19
impl Eig_ for $scalar {
19
- unsafe fn eig(
20
+ fn eig(
20
21
calc_v: bool ,
21
22
l: MatrixLayout ,
22
23
mut a: & mut [ Self ] ,
23
24
) -> Result <( Vec <Self :: Complex >, Vec <Self :: Complex >) > {
24
25
let ( n, _) = l. size( ) ;
25
- let jobvr = if calc_v { b'V' } else { b'N' } ;
26
- let mut w = vec![ Self :: Complex :: zero( ) ; n as usize ] ;
27
- let mut vl = Vec :: new( ) ;
28
- let mut vr = vec![ Self :: Complex :: zero( ) ; ( n * n) as usize ] ;
29
- $ev(
30
- l. lapacke_layout( ) ,
31
- b'N' ,
32
- jobvr,
33
- n,
34
- & mut a,
35
- n,
36
- & mut w,
37
- & mut vl,
38
- n,
39
- & mut vr,
40
- n,
41
- )
42
- . as_lapack_result( ) ?;
43
- Ok ( ( w, vr) )
26
+ // Because LAPACK assumes F-continious array, C-continious array should be taken Hermitian conjugate.
27
+ // However, we utilize a fact that left eigenvector of A^H corresponds to the right eigenvector of A
28
+ let ( jobvl, jobvr) = if calc_v {
29
+ match l {
30
+ MatrixLayout :: C { .. } => ( b'V' , b'N' ) ,
31
+ MatrixLayout :: F { .. } => ( b'N' , b'V' ) ,
32
+ }
33
+ } else {
34
+ ( b'N' , b'N' )
35
+ } ;
36
+ let mut eigs = vec![ Self :: Complex :: zero( ) ; n as usize ] ;
37
+ let mut rwork = vec![ Self :: Real :: zero( ) ; 2 * n as usize ] ;
38
+
39
+ let mut vl = if jobvl == b'V' {
40
+ Some ( vec![ Self :: Complex :: zero( ) ; ( n * n) as usize ] )
41
+ } else {
42
+ None
43
+ } ;
44
+ let mut vr = if jobvr == b'V' {
45
+ Some ( vec![ Self :: Complex :: zero( ) ; ( n * n) as usize ] )
46
+ } else {
47
+ None
48
+ } ;
49
+
50
+ // calc work size
51
+ let mut info = 0 ;
52
+ let mut work_size = [ Self :: zero( ) ] ;
53
+ unsafe {
54
+ $ev(
55
+ jobvl,
56
+ jobvr,
57
+ n,
58
+ & mut a,
59
+ n,
60
+ & mut eigs,
61
+ & mut vl. as_mut( ) . map( |v| v. as_mut_slice( ) ) . unwrap_or( & mut [ ] ) ,
62
+ n,
63
+ & mut vr. as_mut( ) . map( |v| v. as_mut_slice( ) ) . unwrap_or( & mut [ ] ) ,
64
+ n,
65
+ & mut work_size,
66
+ -1 ,
67
+ & mut rwork,
68
+ & mut info,
69
+ )
70
+ } ;
71
+ info. as_lapack_result( ) ?;
72
+
73
+ // actal ev
74
+ let lwork = work_size[ 0 ] . to_usize( ) . unwrap( ) ;
75
+ let mut work = vec![ Self :: zero( ) ; lwork] ;
76
+ unsafe {
77
+ $ev(
78
+ jobvl,
79
+ jobvr,
80
+ n,
81
+ & mut a,
82
+ n,
83
+ & mut eigs,
84
+ & mut vl. as_mut( ) . map( |v| v. as_mut_slice( ) ) . unwrap_or( & mut [ ] ) ,
85
+ n,
86
+ & mut vr. as_mut( ) . map( |v| v. as_mut_slice( ) ) . unwrap_or( & mut [ ] ) ,
87
+ n,
88
+ & mut work,
89
+ lwork as i32 ,
90
+ & mut rwork,
91
+ & mut info,
92
+ )
93
+ } ;
94
+ info. as_lapack_result( ) ?;
95
+
96
+ // Hermite conjugate
97
+ if jobvl == b'V' {
98
+ for c in vl. as_mut( ) . unwrap( ) . iter_mut( ) {
99
+ c. im = -c. im
100
+ }
101
+ }
102
+
103
+ Ok ( ( eigs, vr. or( vl) . unwrap_or( Vec :: new( ) ) ) )
44
104
}
45
105
}
46
106
} ;
47
107
}
48
108
109
+ impl_eig_complex ! ( c64, lapack:: zgeev) ;
110
+ impl_eig_complex ! ( c32, lapack:: cgeev) ;
111
+
49
112
macro_rules! impl_eig_real {
50
113
( $scalar: ty, $ev: path) => {
51
114
impl Eig_ for $scalar {
52
- unsafe fn eig(
115
+ fn eig(
53
116
calc_v: bool ,
54
117
l: MatrixLayout ,
55
118
mut a: & mut [ Self ] ,
56
119
) -> Result <( Vec <Self :: Complex >, Vec <Self :: Complex >) > {
57
120
let ( n, _) = l. size( ) ;
58
121
let jobvr = if calc_v { b'V' } else { b'N' } ;
59
- let mut wr = vec![ Self :: Real :: zero( ) ; n as usize ] ;
60
- let mut wi = vec![ Self :: Real :: zero( ) ; n as usize ] ;
61
- let mut vl = Vec :: new( ) ;
62
- let mut vr = vec![ Self :: Real :: zero( ) ; ( n * n) as usize ] ;
63
- let info = $ev(
64
- l. lapacke_layout( ) ,
65
- b'N' ,
66
- jobvr,
67
- n,
68
- & mut a,
69
- n,
70
- & mut wr,
71
- & mut wi,
72
- & mut vl,
73
- n,
74
- & mut vr,
75
- n,
76
- ) ;
77
- let w: Vec <Self :: Complex > = wr
122
+ let mut wr = vec![ Self :: zero( ) ; n as usize ] ;
123
+ let mut wi = vec![ Self :: zero( ) ; n as usize ] ;
124
+ let mut vr = vec![ Self :: zero( ) ; ( n * n) as usize ] ;
125
+
126
+ // calc work size
127
+ let mut info = 0 ;
128
+ let mut work_size = [ 0.0 ] ;
129
+ unsafe {
130
+ $ev(
131
+ b'N' ,
132
+ jobvr,
133
+ n,
134
+ & mut a,
135
+ n,
136
+ & mut wr,
137
+ & mut wi,
138
+ & mut [ ] ,
139
+ n,
140
+ & mut vr,
141
+ n,
142
+ & mut work_size,
143
+ -1 ,
144
+ & mut info,
145
+ )
146
+ } ;
147
+ info. as_lapack_result( ) ?;
148
+
149
+ // actual ev
150
+ let lwork = work_size[ 0 ] . to_usize( ) . unwrap( ) ;
151
+ let mut work = vec![ Self :: zero( ) ; lwork] ;
152
+ unsafe {
153
+ $ev(
154
+ b'N' ,
155
+ jobvr,
156
+ n,
157
+ & mut a,
158
+ n,
159
+ & mut wr,
160
+ & mut wi,
161
+ & mut [ ] ,
162
+ n,
163
+ & mut vr,
164
+ n,
165
+ & mut work,
166
+ lwork as i32 ,
167
+ & mut info,
168
+ )
169
+ } ;
170
+ info. as_lapack_result( ) ?;
171
+
172
+ let eigs: Vec <Self :: Complex > = wr
78
173
. iter( )
79
174
. zip( wi. iter( ) )
80
175
. map( |( & r, & i) | Self :: Complex :: new( r, i) )
@@ -119,14 +214,11 @@ macro_rules! impl_eig_real {
119
214
} )
120
215
. collect( ) ;
121
216
122
- info. as_lapack_result( ) ?;
123
- Ok ( ( w, v) )
217
+ Ok ( ( eigs, v) )
124
218
}
125
219
}
126
220
} ;
127
221
}
128
222
129
- impl_eig_real ! ( f64 , lapacke:: dgeev) ;
130
- impl_eig_real ! ( f32 , lapacke:: sgeev) ;
131
- impl_eig_complex ! ( c64, lapacke:: zgeev) ;
132
- impl_eig_complex ! ( c32, lapacke:: cgeev) ;
223
+ impl_eig_real ! ( f64 , lapack:: dgeev) ;
224
+ impl_eig_real ! ( f32 , lapack:: sgeev) ;
0 commit comments