@@ -23,8 +23,16 @@ macro_rules! impl_eig_complex {
23
23
mut a: & mut [ Self ] ,
24
24
) -> Result <( Vec <Self :: Complex >, Vec <Self :: Complex >) > {
25
25
let ( n, _) = l. size( ) ;
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
26
+ // LAPACK assumes a column-major input. A row-major input can
27
+ // be interpreted as the transpose of a column-major input. So,
28
+ // for row-major inputs, we we want to solve the following,
29
+ // given the column-major input `A`:
30
+ //
31
+ // A^T V = V Λ ⟺ V^T A = Λ V^T ⟺ conj(V)^H A = Λ conj(V)^H
32
+ //
33
+ // So, in this case, the right eigenvectors are the conjugates
34
+ // of the left eigenvectors computed with `A`, and the
35
+ // eigenvalues are the eigenvalues computed with `A`.
28
36
let ( jobvl, jobvr) = if calc_v {
29
37
match l {
30
38
MatrixLayout :: C { .. } => ( b'V' , b'N' ) ,
@@ -118,8 +126,22 @@ macro_rules! impl_eig_real {
118
126
mut a: & mut [ Self ] ,
119
127
) -> Result <( Vec <Self :: Complex >, Vec <Self :: Complex >) > {
120
128
let ( n, _) = l. size( ) ;
121
- // Because LAPACK assumes F-continious array, C-continious array should be taken Hermitian conjugate.
122
- // However, we utilize a fact that left eigenvector of A^H corresponds to the right eigenvector of A
129
+ // LAPACK assumes a column-major input. A row-major input can
130
+ // be interpreted as the transpose of a column-major input. So,
131
+ // for row-major inputs, we we want to solve the following,
132
+ // given the column-major input `A`:
133
+ //
134
+ // A^T V = V Λ ⟺ V^T A = Λ V^T ⟺ conj(V)^H A = Λ conj(V)^H
135
+ //
136
+ // So, in this case, the right eigenvectors are the conjugates
137
+ // of the left eigenvectors computed with `A`, and the
138
+ // eigenvalues are the eigenvalues computed with `A`.
139
+ //
140
+ // We could conjugate the eigenvalues instead of the
141
+ // eigenvectors, but we have to reconstruct the eigenvectors
142
+ // into new matrices anyway, and by not modifying the
143
+ // eigenvalues, we preserve the nice ordering specified by
144
+ // `sgeev`/`dgeev`.
123
145
let ( jobvl, jobvr) = if calc_v {
124
146
match l {
125
147
MatrixLayout :: C { .. } => ( b'V' , b'N' ) ,
@@ -211,40 +233,34 @@ macro_rules! impl_eig_real {
211
233
// - v(j) = VR(:,j) + i*VR(:,j+1)
212
234
// - v(j+1) = VR(:,j) - i*VR(:,j+1).
213
235
//
214
- // ```
215
- // j -> <----pair----> <----pair---->
216
- // [ ... (real), (imag), (imag), (imag), (imag), ... ] : eigs
217
- // ^ ^ ^ ^ ^
218
- // false false true false true : is_conjugate_pair
219
- // ```
236
+ // In the C-layout case, we need the conjugates of the left
237
+ // eigenvectors, so the signs should be reversed.
238
+
220
239
let n = n as usize ;
221
240
let v = vr. or( vl) . unwrap( ) ;
222
241
let mut eigvecs = unsafe { vec_uninit( n * n) } ;
223
- let mut is_conjugate_pair = false ; // flag for check `j` is complex conjugate
224
- for j in 0 ..n {
225
- if eig_im[ j] == 0.0 {
226
- // j-th eigenvalue is real
227
- for i in 0 ..n {
228
- eigvecs[ i + j * n] = Self :: complex( v[ i + j * n] , 0.0 ) ;
242
+ let mut col = 0 ;
243
+ while col < n {
244
+ if eig_im[ col] == 0. {
245
+ // The corresponding eigenvalue is real.
246
+ for row in 0 ..n {
247
+ let re = v[ row + col * n] ;
248
+ eigvecs[ row + col * n] = Self :: complex( re, 0. ) ;
229
249
}
250
+ col += 1 ;
230
251
} else {
231
- // j-th eigenvalue is complex
232
- // complex conjugated pair can be `j-1` or `j+1`
233
- if is_conjugate_pair {
234
- let j_pair = j - 1 ;
235
- assert!( j_pair < n) ;
236
- for i in 0 ..n {
237
- eigvecs[ i + j * n] = Self :: complex( v[ i + j_pair * n] , v[ i + j * n] ) ;
238
- }
239
- } else {
240
- let j_pair = j + 1 ;
241
- assert!( j_pair < n) ;
242
- for i in 0 ..n {
243
- eigvecs[ i + j * n] =
244
- Self :: complex( v[ i + j * n] , -v[ i + j_pair * n] ) ;
252
+ // This is a complex conjugate pair.
253
+ assert!( col + 1 < n) ;
254
+ for row in 0 ..n {
255
+ let re = v[ row + col * n] ;
256
+ let mut im = v[ row + ( col + 1 ) * n] ;
257
+ if jobvl == b'V' {
258
+ im = -im;
245
259
}
260
+ eigvecs[ row + col * n] = Self :: complex( re, im) ;
261
+ eigvecs[ row + ( col + 1 ) * n] = Self :: complex( re, -im) ;
246
262
}
247
- is_conjugate_pair = !is_conjugate_pair ;
263
+ col += 2 ;
248
264
}
249
265
}
250
266
0 commit comments