11#ifndef EIGEN_ARPACKSELFADJOINTEIGENSOLVER_H
12#define EIGEN_ARPACKSELFADJOINTEIGENSOLVER_H
14#include "../../../../Eigen/Dense"
17#include "./InternalHeaderCheck.h"
22template <
typename Scalar,
typename RealScalar>
24template <
typename MatrixSolver,
typename MatrixType,
typename Scalar,
bool BisSPD>
28template <
typename MatrixType,
typename MatrixSolver = SimplicialLLT<MatrixType>,
bool BisSPD = false>
29class ArpackGeneralizedSelfAdjointEigenSolver {
32 typedef typename MatrixType::Scalar Scalar;
33 typedef typename MatrixType::Index Index;
41 typedef typename NumTraits<Scalar>::Real RealScalar;
48 typedef typename internal::plain_col_type<MatrixType, RealScalar>::type RealVectorType;
56 ArpackGeneralizedSelfAdjointEigenSolver()
59 m_isInitialized(false),
60 m_eigenvectorsOk(false),
86 ArpackGeneralizedSelfAdjointEigenSolver(
const MatrixType &A,
const MatrixType &B, Index nbrEigenvalues,
91 m_isInitialized(false),
92 m_eigenvectorsOk(false),
95 compute(A, B, nbrEigenvalues, eigs_sigma, options, tol);
120 ArpackGeneralizedSelfAdjointEigenSolver(
const MatrixType &A, Index nbrEigenvalues, std::string eigs_sigma =
"LM",
124 m_isInitialized(false),
125 m_eigenvectorsOk(false),
128 compute(A, nbrEigenvalues, eigs_sigma, options, tol);
154 ArpackGeneralizedSelfAdjointEigenSolver &compute(
const MatrixType &A,
const MatrixType &B, Index nbrEigenvalues,
156 RealScalar tol = 0.0);
180 ArpackGeneralizedSelfAdjointEigenSolver &compute(
const MatrixType &A, Index nbrEigenvalues,
182 RealScalar tol = 0.0);
203 const Matrix<Scalar, Dynamic, Dynamic> &eigenvectors()
const {
204 eigen_assert(m_isInitialized &&
"ArpackGeneralizedSelfAdjointEigenSolver is not initialized.");
205 eigen_assert(m_eigenvectorsOk &&
"The eigenvectors have not been computed together with the eigenvalues.");
224 const Matrix<Scalar, Dynamic, 1> &eigenvalues()
const {
225 eigen_assert(m_isInitialized &&
"ArpackGeneralizedSelfAdjointEigenSolver is not initialized.");
247 Matrix<Scalar, Dynamic, Dynamic> operatorSqrt()
const {
248 eigen_assert(m_isInitialized &&
"SelfAdjointEigenSolver is not initialized.");
249 eigen_assert(m_eigenvectorsOk &&
"The eigenvectors have not been computed together with the eigenvalues.");
250 return m_eivec * m_eivalues.cwiseSqrt().asDiagonal() * m_eivec.adjoint();
271 Matrix<Scalar, Dynamic, Dynamic> operatorInverseSqrt()
const {
272 eigen_assert(m_isInitialized &&
"SelfAdjointEigenSolver is not initialized.");
273 eigen_assert(m_eigenvectorsOk &&
"The eigenvectors have not been computed together with the eigenvalues.");
274 return m_eivec * m_eivalues.cwiseInverse().cwiseSqrt().asDiagonal() * m_eivec.adjoint();
282 eigen_assert(m_isInitialized &&
"ArpackGeneralizedSelfAdjointEigenSolver is not initialized.");
286 size_t getNbrConvergedEigenValues()
const {
return m_nbrConverged; }
288 size_t getNbrIterations()
const {
return m_nbrIterations; }
291 Matrix<Scalar, Dynamic, Dynamic> m_eivec;
292 Matrix<Scalar, Dynamic, 1> m_eivalues;
294 bool m_isInitialized;
295 bool m_eigenvectorsOk;
297 size_t m_nbrConverged;
298 size_t m_nbrIterations;
301template <
typename MatrixType,
typename MatrixSolver,
bool BisSPD>
302ArpackGeneralizedSelfAdjointEigenSolver<MatrixType, MatrixSolver, BisSPD> &
303ArpackGeneralizedSelfAdjointEigenSolver<MatrixType, MatrixSolver, BisSPD>::compute(
const MatrixType &A,
304 Index nbrEigenvalues,
305 std::string eigs_sigma,
int options,
308 compute(A, B, nbrEigenvalues, eigs_sigma, options, tol);
313template <
typename MatrixType,
typename MatrixSolver,
bool BisSPD>
314ArpackGeneralizedSelfAdjointEigenSolver<MatrixType, MatrixSolver, BisSPD> &
315ArpackGeneralizedSelfAdjointEigenSolver<MatrixType, MatrixSolver, BisSPD>::compute(
const MatrixType &A,
317 Index nbrEigenvalues,
318 std::string eigs_sigma,
int options,
320 eigen_assert(A.cols() == A.rows());
321 eigen_assert(B.cols() == B.rows());
322 eigen_assert(B.rows() == 0 || A.cols() == B.rows());
323 eigen_assert((options & ~(EigVecMask | GenEigMask)) == 0 && (options & EigVecMask) != EigVecMask &&
324 "invalid option parameter");
326 bool isBempty = (B.rows() == 0) || (B.cols() == 0);
334 int n = (int)A.cols();
342 RealScalar sigma = 0.0;
344 if (eigs_sigma.length() >= 2 && isalpha(eigs_sigma[0]) && isalpha(eigs_sigma[1])) {
345 eigs_sigma[0] = toupper(eigs_sigma[0]);
346 eigs_sigma[1] = toupper(eigs_sigma[1]);
352 if (eigs_sigma.substr(0, 2) !=
"SM") {
353 whch[0] = eigs_sigma[0];
354 whch[1] = eigs_sigma[1];
357 eigen_assert(
false &&
"Specifying clustered eigenvalues is not yet supported!");
362 sigma = atof(eigs_sigma.c_str());
371 if (eigs_sigma.substr(0, 2) ==
"SM" || !(isalpha(eigs_sigma[0]) && isalpha(eigs_sigma[1])) || (!isBempty && !BisSPD))
376 int mode = (bmat[0] ==
'G') + 1;
377 if (eigs_sigma.substr(0, 2) ==
"SM" || !(isalpha(eigs_sigma[0]) && isalpha(eigs_sigma[1]))) {
386 int nev = (int)nbrEigenvalues;
390 Scalar *resid =
new Scalar[n];
396 int ncv = std::min(std::max(2 * nev, 20), n);
400 Scalar *v =
new Scalar[n * ncv];
405 Scalar *workd =
new Scalar[3 * n];
406 int lworkl = ncv * ncv + 8 * ncv;
407 Scalar *workl =
new Scalar[lworkl];
409 int *iparam =
new int[11];
411 iparam[2] = std::max(300, numext::div_ceil(2 * n, std::max(ncv, 1)));
416 int *ipntr =
new int[11];
427 if (mode == 1 || mode == 2) {
428 if (!isBempty) OP.compute(B);
429 }
else if (mode == 3) {
436 MatrixType AminusSigmaB(A);
437 for (Index i = 0; i < A.rows(); ++i) AminusSigmaB.coeffRef(i, i) -= sigma;
439 OP.compute(AminusSigmaB);
441 MatrixType AminusSigmaB = A - sigma * B;
442 OP.compute(AminusSigmaB);
447 if (!(mode == 1 && isBempty) && !(mode == 2 && isBempty) && OP.info() !=
Success) {
455 m_isInitialized =
false;
460 internal::arpack_wrapper<Scalar, RealScalar>::saupd(&ido, bmat, &n, whch, &nev, &tol, resid, &ncv, v, &ldv, iparam,
461 ipntr, workd, workl, &lworkl, &info);
463 if (ido == -1 || ido == 1) {
464 Scalar *in = workd + ipntr[0] - 1;
465 Scalar *out = workd + ipntr[1] - 1;
467 if (ido == 1 && mode != 2) {
468 Scalar *out2 = workd + ipntr[2] - 1;
469 if (isBempty || mode == 1)
474 in = workd + ipntr[2] - 1;
485 internal::OP<MatrixSolver, MatrixType, Scalar, BisSPD>::applyOP(OP, A, n, in, out);
487 }
else if (mode == 2) {
493 }
else if (mode == 3) {
497 if (ido == 1 || isBempty)
502 }
else if (ido == 2) {
503 Scalar *in = workd + ipntr[0] - 1;
504 Scalar *out = workd + ipntr[1] - 1;
506 if (isBempty || mode == 1)
520 eigen_assert(
false &&
"Unknown ARPACK return value!");
528 char howmny[2] =
"A";
532 int *select =
new int[ncv];
536 m_eivalues.resize(nev, 1);
538 internal::arpack_wrapper<Scalar, RealScalar>::seupd(&rvec, howmny, select, m_eivalues.data(), v, &ldv, &sigma, bmat,
539 &n, whch, &nev, &tol, resid, &ncv, v, &ldv, iparam, ipntr,
540 workd, workl, &lworkl, &info);
548 m_eivec.resize(A.rows(), nev);
549 for (
int i = 0; i < nev; i++)
550 for (
int j = 0; j < n; j++) m_eivec(j, i) = v[i * n + j] / scale;
552 if (mode == 1 && !isBempty && BisSPD)
553 internal::OP<MatrixSolver, MatrixType, Scalar, BisSPD>::project(OP, n, nev, m_eivec.data());
555 m_eigenvectorsOk =
true;
558 m_nbrIterations = iparam[2];
559 m_nbrConverged = iparam[4];
574 m_isInitialized = (m_info ==
Success);
581extern "C" void ssaupd_(
int *ido,
char *bmat,
int *n,
char *which,
int *nev,
float *tol,
float *resid,
int *ncv,
582 float *v,
int *ldv,
int *iparam,
int *ipntr,
float *workd,
float *workl,
int *lworkl,
585extern "C" void sseupd_(
int *rvec,
char *All,
int *select,
float *d,
float *z,
int *ldz,
float *sigma,
char *bmat,
586 int *n,
char *which,
int *nev,
float *tol,
float *resid,
int *ncv,
float *v,
int *ldv,
587 int *iparam,
int *ipntr,
float *workd,
float *workl,
int *lworkl,
int *ierr);
591extern "C" void dsaupd_(
int *ido,
char *bmat,
int *n,
char *which,
int *nev,
double *tol,
double *resid,
int *ncv,
592 double *v,
int *ldv,
int *iparam,
int *ipntr,
double *workd,
double *workl,
int *lworkl,
595extern "C" void dseupd_(
int *rvec,
char *All,
int *select,
double *d,
double *z,
int *ldz,
double *sigma,
char *bmat,
596 int *n,
char *which,
int *nev,
double *tol,
double *resid,
int *ncv,
double *v,
int *ldv,
597 int *iparam,
int *ipntr,
double *workd,
double *workl,
int *lworkl,
int *ierr);
601template <
typename Scalar,
typename RealScalar>
602struct arpack_wrapper {
603 static inline void saupd(
int *ido,
char *bmat,
int *n,
char *which,
int *nev, RealScalar *tol, Scalar *resid,
604 int *ncv, Scalar *v,
int *ldv,
int *iparam,
int *ipntr, Scalar *workd, Scalar *workl,
605 int *lworkl,
int *info) {
606 EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL)
609 static inline void seupd(
int *rvec,
char *All,
int *select, Scalar *d, Scalar *z,
int *ldz, RealScalar *sigma,
610 char *bmat,
int *n,
char *which,
int *nev, RealScalar *tol, Scalar *resid,
int *ncv,
611 Scalar *v,
int *ldv,
int *iparam,
int *ipntr, Scalar *workd, Scalar *workl,
int *lworkl,
613 EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL)
618struct arpack_wrapper<float, float> {
619 static inline void saupd(
int *ido,
char *bmat,
int *n,
char *which,
int *nev,
float *tol,
float *resid,
int *ncv,
620 float *v,
int *ldv,
int *iparam,
int *ipntr,
float *workd,
float *workl,
int *lworkl,
622 ssaupd_(ido, bmat, n, which, nev, tol, resid, ncv, v, ldv, iparam, ipntr, workd, workl, lworkl, info);
625 static inline void seupd(
int *rvec,
char *All,
int *select,
float *d,
float *z,
int *ldz,
float *sigma,
char *bmat,
626 int *n,
char *which,
int *nev,
float *tol,
float *resid,
int *ncv,
float *v,
int *ldv,
627 int *iparam,
int *ipntr,
float *workd,
float *workl,
int *lworkl,
int *ierr) {
628 sseupd_(rvec, All, select, d, z, ldz, sigma, bmat, n, which, nev, tol, resid, ncv, v, ldv, iparam, ipntr, workd,
629 workl, lworkl, ierr);
634struct arpack_wrapper<double, double> {
635 static inline void saupd(
int *ido,
char *bmat,
int *n,
char *which,
int *nev,
double *tol,
double *resid,
int *ncv,
636 double *v,
int *ldv,
int *iparam,
int *ipntr,
double *workd,
double *workl,
int *lworkl,
638 dsaupd_(ido, bmat, n, which, nev, tol, resid, ncv, v, ldv, iparam, ipntr, workd, workl, lworkl, info);
641 static inline void seupd(
int *rvec,
char *All,
int *select,
double *d,
double *z,
int *ldz,
double *sigma,
char *bmat,
642 int *n,
char *which,
int *nev,
double *tol,
double *resid,
int *ncv,
double *v,
int *ldv,
643 int *iparam,
int *ipntr,
double *workd,
double *workl,
int *lworkl,
int *ierr) {
644 dseupd_(rvec, All, select, d, v, ldv, sigma, bmat, n, which, nev, tol, resid, ncv, v, ldv, iparam, ipntr, workd,
645 workl, lworkl, ierr);
649template <
typename MatrixSolver,
typename MatrixType,
typename Scalar,
bool BisSPD>
651 static inline void applyOP(MatrixSolver &OP,
const MatrixType &A,
int n, Scalar *in, Scalar *out);
652 static inline void project(MatrixSolver &OP,
int n,
int k, Scalar *vecs);
655template <
typename MatrixSolver,
typename MatrixType,
typename Scalar>
656struct OP<MatrixSolver, MatrixType, Scalar, true> {
657 static inline void applyOP(MatrixSolver &OP,
const MatrixType &A,
int n, Scalar *in, Scalar *out) {
662 Matrix<Scalar, Dynamic, 1>::Map(out, n) = OP.matrixU().solve(Matrix<Scalar, Dynamic, 1>::Map(in, n));
663 Matrix<Scalar, Dynamic, 1>::Map(out, n) = OP.permutationPinv() * Matrix<Scalar, Dynamic, 1>::Map(out, n);
667 Matrix<Scalar, Dynamic, 1>::Map(out, n) = A * Matrix<Scalar, Dynamic, 1>::Map(out, n);
671 Matrix<Scalar, Dynamic, 1>::Map(out, n) = OP.permutationP() * Matrix<Scalar, Dynamic, 1>::Map(out, n);
672 Matrix<Scalar, Dynamic, 1>::Map(out, n) = OP.matrixL().solve(Matrix<Scalar, Dynamic, 1>::Map(out, n));
675 static inline void project(MatrixSolver &OP,
int n,
int k, Scalar *vecs) {
678 Matrix<Scalar, Dynamic, Dynamic>::Map(vecs, n, k) =
679 OP.matrixU().solve(Matrix<Scalar, Dynamic, Dynamic>::Map(vecs, n, k));
680 Matrix<Scalar, Dynamic, Dynamic>::Map(vecs, n, k) =
681 OP.permutationPinv() * Matrix<Scalar, Dynamic, Dynamic>::Map(vecs, n, k);
685template <
typename MatrixSolver,
typename MatrixType,
typename Scalar>
686struct OP<MatrixSolver, MatrixType, Scalar, false> {
687 static inline void applyOP(MatrixSolver &OP,
const MatrixType &A,
int n, Scalar *in, Scalar *out) {
688 eigen_assert(
false &&
"Should never be in here...");
691 static inline void project(MatrixSolver &OP,
int n,
int k, Scalar *vecs) {
692 eigen_assert(
false &&
"Should never be in here...");
Namespace containing all symbols from the Eigen library.