@@ -23,8 +23,16 @@ macro_rules! impl_eig_complex {
2323 mut a: & mut [ Self ] ,
2424 ) -> Result <( Vec <Self :: Complex >, Vec <Self :: Complex >) > {
2525 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`.
2836 let ( jobvl, jobvr) = if calc_v {
2937 match l {
3038 MatrixLayout :: C { .. } => ( b'V' , b'N' ) ,
@@ -118,8 +126,22 @@ macro_rules! impl_eig_real {
118126 mut a: & mut [ Self ] ,
119127 ) -> Result <( Vec <Self :: Complex >, Vec <Self :: Complex >) > {
120128 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`.
123145 let ( jobvl, jobvr) = if calc_v {
124146 match l {
125147 MatrixLayout :: C { .. } => ( b'V' , b'N' ) ,
@@ -211,40 +233,34 @@ macro_rules! impl_eig_real {
211233 // - v(j) = VR(:,j) + i*VR(:,j+1)
212234 // - v(j+1) = VR(:,j) - i*VR(:,j+1).
213235 //
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+
220239 let n = n as usize ;
221240 let v = vr. or( vl) . unwrap( ) ;
222241 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. ) ;
229249 }
250+ col += 1 ;
230251 } 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;
245259 }
260+ eigvecs[ row + col * n] = Self :: complex( re, im) ;
261+ eigvecs[ row + ( col + 1 ) * n] = Self :: complex( re, -im) ;
246262 }
247- is_conjugate_pair = !is_conjugate_pair ;
263+ col += 2 ;
248264 }
249265 }
250266
0 commit comments