ArpackSelfAdjointEigenSolver.h
Go to the documentation of this file.
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2012 David Harmon <dharmon@gmail.com>
5 //
6 // This Source Code Form is subject to the terms of the Mozilla
7 // Public License v. 2.0. If a copy of the MPL was not distributed
8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 
10 #ifndef EIGEN_ARPACKGENERALIZEDSELFADJOINTEIGENSOLVER_H
11 #define EIGEN_ARPACKGENERALIZEDSELFADJOINTEIGENSOLVER_H
12 
13 #include "../../../../Eigen/Dense"
14 
15 #include "./InternalHeaderCheck.h"
16 
17 namespace Eigen {
18 
19 namespace internal {
20  template<typename Scalar, typename RealScalar> struct arpack_wrapper;
21  template<typename MatrixSolver, typename MatrixType, typename Scalar, bool BisSPD> struct OP;
22 }
23 
24 
25 
26 template<typename MatrixType, typename MatrixSolver=SimplicialLLT<MatrixType>, bool BisSPD=false>
28 {
29 public:
30  //typedef typename MatrixSolver::MatrixType MatrixType;
31 
33  typedef typename MatrixType::Scalar Scalar;
34  typedef typename MatrixType::Index Index;
35 
43 
49  typedef typename internal::plain_col_type<MatrixType, RealScalar>::type RealVectorType;
50 
58  : m_eivec(),
59  m_eivalues(),
60  m_isInitialized(false),
61  m_eigenvectorsOk(false),
62  m_nbrConverged(0),
64  { }
65 
89  Index nbrEigenvalues, std::string eigs_sigma="LM",
90  int options=ComputeEigenvectors, RealScalar tol=0.0)
91  : m_eivec(),
92  m_eivalues(),
93  m_isInitialized(false),
94  m_eigenvectorsOk(false),
95  m_nbrConverged(0),
97  {
98  compute(A, B, nbrEigenvalues, eigs_sigma, options, tol);
99  }
100 
124  Index nbrEigenvalues, std::string eigs_sigma="LM",
125  int options=ComputeEigenvectors, RealScalar tol=0.0)
126  : m_eivec(),
127  m_eivalues(),
128  m_isInitialized(false),
129  m_eigenvectorsOk(false),
130  m_nbrConverged(0),
131  m_nbrIterations(0)
132  {
133  compute(A, nbrEigenvalues, eigs_sigma, options, tol);
134  }
135 
136 
161  Index nbrEigenvalues, std::string eigs_sigma="LM",
162  int options=ComputeEigenvectors, RealScalar tol=0.0);
163 
187  Index nbrEigenvalues, std::string eigs_sigma="LM",
188  int options=ComputeEigenvectors, RealScalar tol=0.0);
189 
190 
211  {
212  eigen_assert(m_isInitialized && "ArpackGeneralizedSelfAdjointEigenSolver is not initialized.");
213  eigen_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues.");
214  return m_eivec;
215  }
216 
233  {
234  eigen_assert(m_isInitialized && "ArpackGeneralizedSelfAdjointEigenSolver is not initialized.");
235  return m_eivalues;
236  }
237 
257  {
258  eigen_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized.");
259  eigen_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues.");
260  return m_eivec * m_eivalues.cwiseSqrt().asDiagonal() * m_eivec.adjoint();
261  }
262 
282  {
283  eigen_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized.");
284  eigen_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues.");
285  return m_eivec * m_eivalues.cwiseInverse().cwiseSqrt().asDiagonal() * m_eivec.adjoint();
286  }
287 
293  {
294  eigen_assert(m_isInitialized && "ArpackGeneralizedSelfAdjointEigenSolver is not initialized.");
295  return m_info;
296  }
297 
299  { return m_nbrConverged; }
300 
301  size_t getNbrIterations() const
302  { return m_nbrIterations; }
303 
304 protected:
310 
313 };
314 
315 
316 
317 
318 
319 template<typename MatrixType, typename MatrixSolver, bool BisSPD>
322 ::compute(const MatrixType& A, Index nbrEigenvalues,
323  std::string eigs_sigma, int options, RealScalar tol)
324 {
325  MatrixType B(0,0);
326  compute(A, B, nbrEigenvalues, eigs_sigma, options, tol);
327 
328  return *this;
329 }
330 
331 
332 template<typename MatrixType, typename MatrixSolver, bool BisSPD>
335 ::compute(const MatrixType& A, const MatrixType& B, Index nbrEigenvalues,
336  std::string eigs_sigma, int options, RealScalar tol)
337 {
338  eigen_assert(A.cols() == A.rows());
339  eigen_assert(B.cols() == B.rows());
340  eigen_assert(B.rows() == 0 || A.cols() == B.rows());
341  eigen_assert((options &~ (EigVecMask | GenEigMask)) == 0
342  && (options & EigVecMask) != EigVecMask
343  && "invalid option parameter");
344 
345  bool isBempty = (B.rows() == 0) || (B.cols() == 0);
346 
347  // For clarity, all parameters match their ARPACK name
348  //
349  // Always 0 on the first call
350  //
351  int ido = 0;
352 
353  int n = (int)A.cols();
354 
355  // User options: "LA", "SA", "SM", "LM", "BE"
356  //
357  char whch[3] = "LM";
358 
359  // Specifies the shift if iparam[6] = { 3, 4, 5 }, not used if iparam[6] = { 1, 2 }
360  //
361  RealScalar sigma = 0.0;
362 
363  if (eigs_sigma.length() >= 2 && isalpha(eigs_sigma[0]) && isalpha(eigs_sigma[1]))
364  {
365  eigs_sigma[0] = toupper(eigs_sigma[0]);
366  eigs_sigma[1] = toupper(eigs_sigma[1]);
367 
368  // In the following special case we're going to invert the problem, since solving
369  // for larger magnitude is much much faster
370  // i.e., if 'SM' is specified, we're going to really use 'LM', the default
371  //
372  if (eigs_sigma.substr(0,2) != "SM")
373  {
374  whch[0] = eigs_sigma[0];
375  whch[1] = eigs_sigma[1];
376  }
377  }
378  else
379  {
380  eigen_assert(false && "Specifying clustered eigenvalues is not yet supported!");
381 
382  // If it's not scalar values, then the user may be explicitly
383  // specifying the sigma value to cluster the evs around
384  //
385  sigma = atof(eigs_sigma.c_str());
386 
387  // If atof fails, it returns 0.0, which is a fine default
388  //
389  }
390 
391  // "I" means normal eigenvalue problem, "G" means generalized
392  //
393  char bmat[2] = "I";
394  if (eigs_sigma.substr(0,2) == "SM" || !(isalpha(eigs_sigma[0]) && isalpha(eigs_sigma[1])) || (!isBempty && !BisSPD))
395  bmat[0] = 'G';
396 
397  // Now we determine the mode to use
398  //
399  int mode = (bmat[0] == 'G') + 1;
400  if (eigs_sigma.substr(0,2) == "SM" || !(isalpha(eigs_sigma[0]) && isalpha(eigs_sigma[1])))
401  {
402  // We're going to use shift-and-invert mode, and basically find
403  // the largest eigenvalues of the inverse operator
404  //
405  mode = 3;
406  }
407 
408  // The user-specified number of eigenvalues/vectors to compute
409  //
410  int nev = (int)nbrEigenvalues;
411 
412  // Allocate space for ARPACK to store the residual
413  //
414  Scalar *resid = new Scalar[n];
415 
416  // Number of Lanczos vectors, must satisfy nev < ncv <= n
417  // Note that this indicates that nev != n, and we cannot compute
418  // all eigenvalues of a mtrix
419  //
420  int ncv = std::min(std::max(2*nev, 20), n);
421 
422  // The working n x ncv matrix, also store the final eigenvectors (if computed)
423  //
424  Scalar *v = new Scalar[n*ncv];
425  int ldv = n;
426 
427  // Working space
428  //
429  Scalar *workd = new Scalar[3*n];
430  int lworkl = ncv*ncv+8*ncv; // Must be at least this length
431  Scalar *workl = new Scalar[lworkl];
432 
433  int *iparam= new int[11];
434  iparam[0] = 1; // 1 means we let ARPACK perform the shifts, 0 means we'd have to do it
435  iparam[2] = std::max(300, (int)std::ceil(2*n/std::max(ncv,1)));
436  iparam[6] = mode; // The mode, 1 is standard ev problem, 2 for generalized ev, 3 for shift-and-invert
437 
438  // Used during reverse communicate to notify where arrays start
439  //
440  int *ipntr = new int[11];
441 
442  // Error codes are returned in here, initial value of 0 indicates a random initial
443  // residual vector is used, any other values means resid contains the initial residual
444  // vector, possibly from a previous run
445  //
446  int info = 0;
447 
448  Scalar scale = 1.0;
449  //if (!isBempty)
450  //{
451  //Scalar scale = B.norm() / std::sqrt(n);
452  //scale = std::pow(2, std::floor(std::log(scale+1)));
454  //for (size_t i=0; i<(size_t)B.outerSize(); i++)
455  // for (typename MatrixType::InnerIterator it(B, i); it; ++it)
456  // it.valueRef() /= scale;
457  //}
458 
459  MatrixSolver OP;
460  if (mode == 1 || mode == 2)
461  {
462  if (!isBempty)
463  OP.compute(B);
464  }
465  else if (mode == 3)
466  {
467  if (sigma == 0.0)
468  {
469  OP.compute(A);
470  }
471  else
472  {
473  // Note: We will never enter here because sigma must be 0.0
474  //
475  if (isBempty)
476  {
477  MatrixType AminusSigmaB(A);
478  for (Index i=0; i<A.rows(); ++i)
479  AminusSigmaB.coeffRef(i,i) -= sigma;
480 
481  OP.compute(AminusSigmaB);
482  }
483  else
484  {
485  MatrixType AminusSigmaB = A - sigma * B;
486  OP.compute(AminusSigmaB);
487  }
488  }
489  }
490 
491  if (!(mode == 1 && isBempty) && !(mode == 2 && isBempty) && OP.info() != Success)
492  std::cout << "Error factoring matrix" << std::endl;
493 
494  do
495  {
496  internal::arpack_wrapper<Scalar, RealScalar>::saupd(&ido, bmat, &n, whch, &nev, &tol, resid,
497  &ncv, v, &ldv, iparam, ipntr, workd, workl,
498  &lworkl, &info);
499 
500  if (ido == -1 || ido == 1)
501  {
502  Scalar *in = workd + ipntr[0] - 1;
503  Scalar *out = workd + ipntr[1] - 1;
504 
505  if (ido == 1 && mode != 2)
506  {
507  Scalar *out2 = workd + ipntr[2] - 1;
508  if (isBempty || mode == 1)
510  else
512 
513  in = workd + ipntr[2] - 1;
514  }
515 
516  if (mode == 1)
517  {
518  if (isBempty)
519  {
520  // OP = A
521  //
523  }
524  else
525  {
526  // OP = L^{-1}AL^{-T}
527  //
528  internal::OP<MatrixSolver, MatrixType, Scalar, BisSPD>::applyOP(OP, A, n, in, out);
529  }
530  }
531  else if (mode == 2)
532  {
533  if (ido == 1)
535 
536  // OP = B^{-1} A
537  //
539  }
540  else if (mode == 3)
541  {
542  // OP = (A-\sigmaB)B (\sigma could be 0, and B could be I)
543  // The B * in is already computed and stored at in if ido == 1
544  //
545  if (ido == 1 || isBempty)
547  else
549  }
550  }
551  else if (ido == 2)
552  {
553  Scalar *in = workd + ipntr[0] - 1;
554  Scalar *out = workd + ipntr[1] - 1;
555 
556  if (isBempty || mode == 1)
558  else
560  }
561  } while (ido != 99);
562 
563  if (info == 1)
564  m_info = NoConvergence;
565  else if (info == 3)
566  m_info = NumericalIssue;
567  else if (info < 0)
568  m_info = InvalidInput;
569  else if (info != 0)
570  eigen_assert(false && "Unknown ARPACK return value!");
571  else
572  {
573  // Do we compute eigenvectors or not?
574  //
575  int rvec = (options & ComputeEigenvectors) == ComputeEigenvectors;
576 
577  // "A" means "All", use "S" to choose specific eigenvalues (not yet supported in ARPACK))
578  //
579  char howmny[2] = "A";
580 
581  // if howmny == "S", specifies the eigenvalues to compute (not implemented in ARPACK)
582  //
583  int *select = new int[ncv];
584 
585  // Final eigenvalues
586  //
587  m_eivalues.resize(nev, 1);
588 
589  internal::arpack_wrapper<Scalar, RealScalar>::seupd(&rvec, howmny, select, m_eivalues.data(), v, &ldv,
590  &sigma, bmat, &n, whch, &nev, &tol, resid, &ncv,
591  v, &ldv, iparam, ipntr, workd, workl, &lworkl, &info);
592 
593  if (info == -14)
594  m_info = NoConvergence;
595  else if (info != 0)
596  m_info = InvalidInput;
597  else
598  {
599  if (rvec)
600  {
601  m_eivec.resize(A.rows(), nev);
602  for (int i=0; i<nev; i++)
603  for (int j=0; j<n; j++)
604  m_eivec(j,i) = v[i*n+j] / scale;
605 
606  if (mode == 1 && !isBempty && BisSPD)
607  internal::OP<MatrixSolver, MatrixType, Scalar, BisSPD>::project(OP, n, nev, m_eivec.data());
608 
609  m_eigenvectorsOk = true;
610  }
611 
612  m_nbrIterations = iparam[2];
613  m_nbrConverged = iparam[4];
614 
615  m_info = Success;
616  }
617 
618  delete[] select;
619  }
620 
621  delete[] v;
622  delete[] iparam;
623  delete[] ipntr;
624  delete[] workd;
625  delete[] workl;
626  delete[] resid;
627 
628  m_isInitialized = true;
629 
630  return *this;
631 }
632 
633 
634 // Single precision
635 //
636 extern "C" void ssaupd_(int *ido, char *bmat, int *n, char *which,
637  int *nev, float *tol, float *resid, int *ncv,
638  float *v, int *ldv, int *iparam, int *ipntr,
639  float *workd, float *workl, int *lworkl,
640  int *info);
641 
642 extern "C" void sseupd_(int *rvec, char *All, int *select, float *d,
643  float *z, int *ldz, float *sigma,
644  char *bmat, int *n, char *which, int *nev,
645  float *tol, float *resid, int *ncv, float *v,
646  int *ldv, int *iparam, int *ipntr, float *workd,
647  float *workl, int *lworkl, int *ierr);
648 
649 // Double precision
650 //
651 extern "C" void dsaupd_(int *ido, char *bmat, int *n, char *which,
652  int *nev, double *tol, double *resid, int *ncv,
653  double *v, int *ldv, int *iparam, int *ipntr,
654  double *workd, double *workl, int *lworkl,
655  int *info);
656 
657 extern "C" void dseupd_(int *rvec, char *All, int *select, double *d,
658  double *z, int *ldz, double *sigma,
659  char *bmat, int *n, char *which, int *nev,
660  double *tol, double *resid, int *ncv, double *v,
661  int *ldv, int *iparam, int *ipntr, double *workd,
662  double *workl, int *lworkl, int *ierr);
663 
664 
665 namespace internal {
666 
667 template<typename Scalar, typename RealScalar> struct arpack_wrapper
668 {
669  static inline void saupd(int *ido, char *bmat, int *n, char *which,
670  int *nev, RealScalar *tol, Scalar *resid, int *ncv,
671  Scalar *v, int *ldv, int *iparam, int *ipntr,
672  Scalar *workd, Scalar *workl, int *lworkl, int *info)
673  {
674  EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL)
675  }
676 
677  static inline void seupd(int *rvec, char *All, int *select, Scalar *d,
678  Scalar *z, int *ldz, RealScalar *sigma,
679  char *bmat, int *n, char *which, int *nev,
680  RealScalar *tol, Scalar *resid, int *ncv, Scalar *v,
681  int *ldv, int *iparam, int *ipntr, Scalar *workd,
682  Scalar *workl, int *lworkl, int *ierr)
683  {
684  EIGEN_STATIC_ASSERT(!NumTraits<Scalar>::IsComplex, NUMERIC_TYPE_MUST_BE_REAL)
685  }
686 };
687 
688 template <> struct arpack_wrapper<float, float>
689 {
690  static inline void saupd(int *ido, char *bmat, int *n, char *which,
691  int *nev, float *tol, float *resid, int *ncv,
692  float *v, int *ldv, int *iparam, int *ipntr,
693  float *workd, float *workl, int *lworkl, int *info)
694  {
695  ssaupd_(ido, bmat, n, which, nev, tol, resid, ncv, v, ldv, iparam, ipntr, workd, workl, lworkl, info);
696  }
697 
698  static inline void seupd(int *rvec, char *All, int *select, float *d,
699  float *z, int *ldz, float *sigma,
700  char *bmat, int *n, char *which, int *nev,
701  float *tol, float *resid, int *ncv, float *v,
702  int *ldv, int *iparam, int *ipntr, float *workd,
703  float *workl, int *lworkl, int *ierr)
704  {
705  sseupd_(rvec, All, select, d, z, ldz, sigma, bmat, n, which, nev, tol, resid, ncv, v, ldv, iparam, ipntr,
706  workd, workl, lworkl, ierr);
707  }
708 };
709 
710 template <> struct arpack_wrapper<double, double>
711 {
712  static inline void saupd(int *ido, char *bmat, int *n, char *which,
713  int *nev, double *tol, double *resid, int *ncv,
714  double *v, int *ldv, int *iparam, int *ipntr,
715  double *workd, double *workl, int *lworkl, int *info)
716  {
717  dsaupd_(ido, bmat, n, which, nev, tol, resid, ncv, v, ldv, iparam, ipntr, workd, workl, lworkl, info);
718  }
719 
720  static inline void seupd(int *rvec, char *All, int *select, double *d,
721  double *z, int *ldz, double *sigma,
722  char *bmat, int *n, char *which, int *nev,
723  double *tol, double *resid, int *ncv, double *v,
724  int *ldv, int *iparam, int *ipntr, double *workd,
725  double *workl, int *lworkl, int *ierr)
726  {
727  dseupd_(rvec, All, select, d, v, ldv, sigma, bmat, n, which, nev, tol, resid, ncv, v, ldv, iparam, ipntr,
728  workd, workl, lworkl, ierr);
729  }
730 };
731 
732 
733 template<typename MatrixSolver, typename MatrixType, typename Scalar, bool BisSPD>
734 struct OP
735 {
736  static inline void applyOP(MatrixSolver &OP, const MatrixType &A, int n, Scalar *in, Scalar *out);
737  static inline void project(MatrixSolver &OP, int n, int k, Scalar *vecs);
738 };
739 
740 template<typename MatrixSolver, typename MatrixType, typename Scalar>
741 struct OP<MatrixSolver, MatrixType, Scalar, true>
742 {
743  static inline void applyOP(MatrixSolver &OP, const MatrixType &A, int n, Scalar *in, Scalar *out)
744 {
745  // OP = L^{-1} A L^{-T} (B = LL^T)
746  //
747  // First solve L^T out = in
748  //
749  Matrix<Scalar, Dynamic, 1>::Map(out, n) = OP.matrixU().solve(Matrix<Scalar, Dynamic, 1>::Map(in, n));
750  Matrix<Scalar, Dynamic, 1>::Map(out, n) = OP.permutationPinv() * Matrix<Scalar, Dynamic, 1>::Map(out, n);
751 
752  // Then compute out = A out
753  //
755 
756  // Then solve L out = out
757  //
758  Matrix<Scalar, Dynamic, 1>::Map(out, n) = OP.permutationP() * Matrix<Scalar, Dynamic, 1>::Map(out, n);
759  Matrix<Scalar, Dynamic, 1>::Map(out, n) = OP.matrixL().solve(Matrix<Scalar, Dynamic, 1>::Map(out, n));
760 }
761 
762  static inline void project(MatrixSolver &OP, int n, int k, Scalar *vecs)
763 {
764  // Solve L^T out = in
765  //
766  Matrix<Scalar, Dynamic, Dynamic>::Map(vecs, n, k) = OP.matrixU().solve(Matrix<Scalar, Dynamic, Dynamic>::Map(vecs, n, k));
767  Matrix<Scalar, Dynamic, Dynamic>::Map(vecs, n, k) = OP.permutationPinv() * Matrix<Scalar, Dynamic, Dynamic>::Map(vecs, n, k);
768 }
769 
770 };
771 
772 template<typename MatrixSolver, typename MatrixType, typename Scalar>
773 struct OP<MatrixSolver, MatrixType, Scalar, false>
774 {
775  static inline void applyOP(MatrixSolver &OP, const MatrixType &A, int n, Scalar *in, Scalar *out)
776 {
777  eigen_assert(false && "Should never be in here...");
778 }
779 
780  static inline void project(MatrixSolver &OP, int n, int k, Scalar *vecs)
781 {
782  eigen_assert(false && "Should never be in here...");
783 }
784 
785 };
786 
787 } // end namespace internal
788 
789 } // end namespace Eigen
790 
791 #endif // EIGEN_ARPACKSELFADJOINTEIGENSOLVER_H
792 
Array< int, Dynamic, 1 > v
solver compute(A)
int n
SparseMatrix< double > A(n, n)
int i
MatrixXf B
#define eigen_assert(x)
#define EIGEN_STATIC_ASSERT(X, MSG)
Matrix< float, 1, Dynamic > MatrixType
const Matrix< Scalar, Dynamic, Dynamic > & eigenvectors() const
Returns the eigenvectors of given matrix.
ArpackGeneralizedSelfAdjointEigenSolver & compute(const MatrixType &A, const MatrixType &B, Index nbrEigenvalues, std::string eigs_sigma="LM", int options=ComputeEigenvectors, RealScalar tol=0.0)
Computes generalized eigenvalues / eigenvectors of given matrix using the external ARPACK library.
NumTraits< Scalar >::Real RealScalar
Real scalar type for MatrixType.
internal::plain_col_type< MatrixType, RealScalar >::type RealVectorType
Type for vector of eigenvalues as returned by eigenvalues().
ComputationInfo info() const
Reports whether previous computation was successful.
Matrix< Scalar, Dynamic, Dynamic > operatorSqrt() const
Computes the positive-definite square root of the matrix.
ArpackGeneralizedSelfAdjointEigenSolver(const MatrixType &A, Index nbrEigenvalues, std::string eigs_sigma="LM", int options=ComputeEigenvectors, RealScalar tol=0.0)
Constructor; computes eigenvalues of given matrix.
MatrixType::Scalar Scalar
Scalar type for matrices of type MatrixType.
const Matrix< Scalar, Dynamic, 1 > & eigenvalues() const
Returns the eigenvalues of given matrix.
ArpackGeneralizedSelfAdjointEigenSolver(const MatrixType &A, const MatrixType &B, Index nbrEigenvalues, std::string eigs_sigma="LM", int options=ComputeEigenvectors, RealScalar tol=0.0)
Constructor; computes generalized eigenvalues of given matrix with respect to another matrix.
Matrix< Scalar, Dynamic, Dynamic > operatorInverseSqrt() const
Computes the inverse square root of the matrix.
ComputationInfo
NumericalIssue
ComputeEigenvectors
: TensorContractionSycl.h, provides various tensor contraction kernel for SYCL backend
void dseupd_(int *rvec, char *All, int *select, double *d, double *z, int *ldz, double *sigma, char *bmat, int *n, char *which, int *nev, double *tol, double *resid, int *ncv, double *v, int *ldv, int *iparam, int *ipntr, double *workd, double *workl, int *lworkl, int *ierr)
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
CleanedUpDerType< DerType >::type() min(const AutoDiffScalar< DerType > &x, const T &y)
CleanedUpDerType< DerType >::type() max(const AutoDiffScalar< DerType > &x, const T &y)
void sseupd_(int *rvec, char *All, int *select, float *d, float *z, int *ldz, float *sigma, char *bmat, int *n, char *which, int *nev, float *tol, float *resid, int *ncv, float *v, int *ldv, int *iparam, int *ipntr, float *workd, float *workl, int *lworkl, int *ierr)
void ssaupd_(int *ido, char *bmat, int *n, char *which, int *nev, float *tol, float *resid, int *ncv, float *v, int *ldv, int *iparam, int *ipntr, float *workd, float *workl, int *lworkl, int *info)
void dsaupd_(int *ido, char *bmat, int *n, char *which, int *nev, double *tol, double *resid, int *ncv, double *v, int *ldv, int *iparam, int *ipntr, double *workd, double *workl, int *lworkl, int *info)
std::ptrdiff_t j