Skip to content

Commit 802149b

Browse files
committed
Reconstruct eigenvectors
1 parent 4737b9c commit 802149b

File tree

1 file changed

+56
-48
lines changed

1 file changed

+56
-48
lines changed

lax/src/eig.rs

Lines changed: 56 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -223,59 +223,67 @@ macro_rules! impl_eig_real {
223223
.map(|(&re, &im)| Self::complex(re, im))
224224
.collect();
225225

226-
if !calc_v {
227-
return Ok((eigs, Vec::new()));
228-
}
229-
230-
// Reconstruct eigenvectors into complex-array
231-
// --------------------------------------------
232-
//
233-
// From LAPACK API https://software.intel.com/en-us/node/469230
234-
//
235-
// - If the j-th eigenvalue is real,
236-
// - v(j) = VR(:,j), the j-th column of VR.
237-
//
238-
// - If the j-th and (j+1)-st eigenvalues form a complex conjugate pair,
239-
// - v(j) = VR(:,j) + i*VR(:,j+1)
240-
// - v(j+1) = VR(:,j) - i*VR(:,j+1).
241-
//
242-
// In the C-layout case, we need the conjugates of the left
243-
// eigenvectors, so the signs should be reversed.
244-
245-
let n = n as usize;
246-
let v = vr.or(vl).unwrap();
247-
let mut eigvecs: Vec<MaybeUninit<Self::Complex>> = vec_uninit(n * n);
248-
let mut col = 0;
249-
while col < n {
250-
if eig_im[col] == 0. {
251-
// The corresponding eigenvalue is real.
252-
for row in 0..n {
253-
let re = v[row + col * n];
254-
eigvecs[row + col * n].write(Self::complex(re, 0.));
255-
}
256-
col += 1;
257-
} else {
258-
// This is a complex conjugate pair.
259-
assert!(col + 1 < n);
260-
for row in 0..n {
261-
let re = v[row + col * n];
262-
let mut im = v[row + (col + 1) * n];
263-
if jobvl.is_calc() {
264-
im = -im;
265-
}
266-
eigvecs[row + col * n].write(Self::complex(re, im));
267-
eigvecs[row + (col + 1) * n].write(Self::complex(re, -im));
268-
}
269-
col += 2;
270-
}
226+
if calc_v {
227+
let eigvecs = reconstruct_eigenvectors(jobvl, n, &eig_im, vr, vl);
228+
Ok((eigs, eigvecs))
229+
} else {
230+
Ok((eigs, Vec::new()))
271231
}
272-
let eigvecs = unsafe { eigvecs.assume_init() };
273-
274-
Ok((eigs, eigvecs))
275232
}
276233
}
277234
};
278235
}
279236

280237
impl_eig_real!(f64, lapack_sys::dgeev_);
281238
impl_eig_real!(f32, lapack_sys::sgeev_);
239+
240+
/// Reconstruct eigenvectors into complex-array
241+
/// --------------------------------------------
242+
///
243+
/// From LAPACK API https://software.intel.com/en-us/node/469230
244+
///
245+
/// - If the j-th eigenvalue is real,
246+
/// - v(j) = VR(:,j), the j-th column of VR.
247+
///
248+
/// - If the j-th and (j+1)-st eigenvalues form a complex conjugate pair,
249+
/// - v(j) = VR(:,j) + i*VR(:,j+1)
250+
/// - v(j+1) = VR(:,j) - i*VR(:,j+1).
251+
///
252+
/// In the C-layout case, we need the conjugates of the left
253+
/// eigenvectors, so the signs should be reversed.
254+
fn reconstruct_eigenvectors<T: Scalar>(
255+
jobvl: JobEv,
256+
n: i32,
257+
eig_im: &[T],
258+
vr: Option<Vec<T>>,
259+
vl: Option<Vec<T>>,
260+
) -> Vec<T::Complex> {
261+
let n = n as usize;
262+
let v = vr.or(vl).unwrap();
263+
let mut eigvecs: Vec<MaybeUninit<T::Complex>> = vec_uninit(n * n);
264+
let mut col = 0;
265+
while col < n {
266+
if eig_im[col].is_zero() {
267+
// The corresponding eigenvalue is real.
268+
for row in 0..n {
269+
let re = v[row + col * n];
270+
eigvecs[row + col * n].write(T::complex(re, T::zero()));
271+
}
272+
col += 1;
273+
} else {
274+
// This is a complex conjugate pair.
275+
assert!(col + 1 < n);
276+
for row in 0..n {
277+
let re = v[row + col * n];
278+
let mut im = v[row + (col + 1) * n];
279+
if jobvl.is_calc() {
280+
im = -im;
281+
}
282+
eigvecs[row + col * n].write(T::complex(re, im));
283+
eigvecs[row + (col + 1) * n].write(T::complex(re, -im));
284+
}
285+
col += 2;
286+
}
287+
}
288+
unsafe { eigvecs.assume_init() }
289+
}

0 commit comments

Comments
 (0)