Skip to content

Commit 0a78593

Browse files
committed
Reconstruct eigenvectors
1 parent 7b8ee70 commit 0a78593

File tree

1 file changed

+60
-48
lines changed

1 file changed

+60
-48
lines changed

lax/src/eig.rs

Lines changed: 60 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -429,59 +429,71 @@ macro_rules! impl_eig_real {
429429
.map(|(&re, &im)| Self::complex(re, im))
430430
.collect();
431431

432-
if !calc_v {
433-
return Ok((eigs, Vec::new()));
434-
}
435-
436-
// Reconstruct eigenvectors into complex-array
437-
// --------------------------------------------
438-
//
439-
// From LAPACK API https://software.intel.com/en-us/node/469230
440-
//
441-
// - If the j-th eigenvalue is real,
442-
// - v(j) = VR(:,j), the j-th column of VR.
443-
//
444-
// - If the j-th and (j+1)-st eigenvalues form a complex conjugate pair,
445-
// - v(j) = VR(:,j) + i*VR(:,j+1)
446-
// - v(j+1) = VR(:,j) - i*VR(:,j+1).
447-
//
448-
// In the C-layout case, we need the conjugates of the left
449-
// eigenvectors, so the signs should be reversed.
450-
451-
let n = n as usize;
452-
let v = vr.or(vl).unwrap();
453-
let mut eigvecs: Vec<MaybeUninit<Self::Complex>> = vec_uninit(n * n);
454-
let mut col = 0;
455-
while col < n {
456-
if eig_im[col] == 0. {
457-
// The corresponding eigenvalue is real.
458-
for row in 0..n {
459-
let re = v[row + col * n];
460-
eigvecs[row + col * n].write(Self::complex(re, 0.));
461-
}
462-
col += 1;
463-
} else {
464-
// This is a complex conjugate pair.
465-
assert!(col + 1 < n);
466-
for row in 0..n {
467-
let re = v[row + col * n];
468-
let mut im = v[row + (col + 1) * n];
469-
if jobvl.is_calc() {
470-
im = -im;
471-
}
472-
eigvecs[row + col * n].write(Self::complex(re, im));
473-
eigvecs[row + (col + 1) * n].write(Self::complex(re, -im));
474-
}
475-
col += 2;
476-
}
432+
if calc_v {
433+
let mut eigvecs = vec_uninit((n * n) as usize);
434+
reconstruct_eigenvectors(
435+
jobvl.is_calc(),
436+
&eig_im,
437+
&vr.or(vl).unwrap(),
438+
&mut eigvecs,
439+
);
440+
Ok((eigs, unsafe { eigvecs.assume_init() }))
441+
} else {
442+
Ok((eigs, Vec::new()))
477443
}
478-
let eigvecs = unsafe { eigvecs.assume_init() };
479-
480-
Ok((eigs, eigvecs))
481444
}
482445
}
483446
};
484447
}
485448

486449
impl_eig_real!(f64, lapack_sys::dgeev_);
487450
impl_eig_real!(f32, lapack_sys::sgeev_);
451+
452+
/// Reconstruct eigenvectors into complex-array
453+
///
454+
/// From LAPACK API https://software.intel.com/en-us/node/469230
455+
///
456+
/// - If the j-th eigenvalue is real,
457+
/// - v(j) = VR(:,j), the j-th column of VR.
458+
///
459+
/// - If the j-th and (j+1)-st eigenvalues form a complex conjugate pair,
460+
/// - v(j) = VR(:,j) + i*VR(:,j+1)
461+
/// - v(j+1) = VR(:,j) - i*VR(:,j+1).
462+
///
463+
/// In the C-layout case, we need the conjugates of the left
464+
/// eigenvectors, so the signs should be reversed.
465+
fn reconstruct_eigenvectors<T: Scalar>(
466+
take_hermite_conjugate: bool,
467+
eig_im: &[T],
468+
vr: &[T],
469+
vc: &mut [MaybeUninit<T::Complex>],
470+
) {
471+
let n = eig_im.len();
472+
assert_eq!(vr.len(), n * n);
473+
assert_eq!(vc.len(), n * n);
474+
475+
let mut col = 0;
476+
while col < n {
477+
if eig_im[col].is_zero() {
478+
// The corresponding eigenvalue is real.
479+
for row in 0..n {
480+
let re = vr[row + col * n];
481+
vc[row + col * n].write(T::complex(re, T::zero()));
482+
}
483+
col += 1;
484+
} else {
485+
// This is a complex conjugate pair.
486+
assert!(col + 1 < n);
487+
for row in 0..n {
488+
let re = vr[row + col * n];
489+
let mut im = vr[row + (col + 1) * n];
490+
if take_hermite_conjugate {
491+
im = -im;
492+
}
493+
vc[row + col * n].write(T::complex(re, im));
494+
vc[row + (col + 1) * n].write(T::complex(re, -im));
495+
}
496+
col += 2;
497+
}
498+
}
499+
}

0 commit comments

Comments
 (0)