ARPACK-Armadillo
GenEigsSolver.h
1 // Copyright (C) 2015 Yixuan Qiu
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #ifndef GEN_EIGS_SOLVER_H
8 #define GEN_EIGS_SOLVER_H
9 
10 #include <armadillo>
11 #include <vector> // std::vector
12 #include <cmath> // std::abs, std::pow, std::sqrt
13 #include <algorithm> // std::max, std::min
14 #include <complex> // std::complex, std::conj, std::norm
15 #include <limits> // std::numeric_limits
16 #include <stdexcept> // std::invalid_argument
17 
18 #include "SelectionRule.h"
19 #include "LinAlg/UpperHessenbergQR.h"
20 #include "LinAlg/DoubleShiftQR.h"
21 #include "LinAlg/UpperHessenbergEigen.h"
22 #include "MatOp/DenseGenMatProd.h"
23 #include "MatOp/DenseGenRealShiftSolve.h"
24 
25 
80 template < typename Scalar = double,
81  int SelectionRule = LARGEST_MAGN,
82  typename OpType = DenseGenMatProd<double> >
84 {
85 private:
86  typedef arma::Mat<Scalar> Matrix;
87  typedef arma::Col<Scalar> Vector;
88  typedef arma::uvec BoolVector;
89 
90  typedef std::complex<Scalar> Complex;
91  typedef arma::Mat<Complex> ComplexMatrix;
92  typedef arma::Col<Complex> ComplexVector;
93 
94 protected:
95  OpType *op; // object to conduct matrix operation,
96  // e.g. matrix-vector product
97 
98 private:
99  const int dim_n; // dimension of matrix A
100 
101 protected:
102  const int nev; // number of eigenvalues requested
103 
104 private:
105  const int ncv; // number of ritz values
106  int nmatop; // number of matrix operations called
107  int niter; // number of restarting iterations
108 
109  Matrix fac_V; // V matrix in the Arnoldi factorization
110  Matrix fac_H; // H matrix in the Arnoldi factorization
111  Vector fac_f; // residual in the Arnoldi factorization
112 
113 protected:
114  ComplexVector ritz_val; // ritz values
115 
116 private:
117  ComplexMatrix ritz_vec; // ritz vectors
118  BoolVector ritz_conv; // indicator of the convergence of ritz values
119 
120  const Scalar prec; // precision parameter used to test convergence
121  // prec = epsilon^(2/3)
122  // epsilon is the machine precision,
123  // e.g. ~= 1e-16 for the "double" type
124 
125  // Arnoldi factorization starting from step-k
126  inline void factorize_from(int from_k, int to_m, const Vector &fk);
127 
128  static bool is_complex(Complex v, Scalar eps)
129  {
130  return std::abs(v.imag()) > eps;
131  }
132 
133  static bool is_conj(Complex v1, Complex v2, Scalar eps)
134  {
135  return std::abs(v1 - std::conj(v2)) < eps;
136  }
137 
138  // Implicitly restarted Arnoldi factorization
139  inline void restart(int k);
140 
141  // Calculate the number of converged Ritz values
142  inline int num_converged(Scalar tol);
143 
144  // Return the adjusted nev for restarting
145  inline int nev_adjusted(int nconv);
146 
147  // Retrieve and sort ritz values and ritz vectors
148  inline void retrieve_ritzpair();
149 
150 protected:
151  // Sort the first nev Ritz pairs in decreasing magnitude order
152  // This is used to return the final results
153  inline virtual void sort_ritzpair();
154 
155 public:
173  GenEigsSolver(OpType *op_, int nev_, int ncv_) :
174  op(op_),
175  dim_n(op->rows()),
176  nev(nev_),
177  ncv(ncv_ > dim_n ? dim_n : ncv_),
178  nmatop(0),
179  niter(0),
180  prec(std::pow(std::numeric_limits<Scalar>::epsilon(), Scalar(2.0) / 3))
181  {
182  if(nev_ < 1 || nev_ > dim_n - 2)
183  throw std::invalid_argument("nev must satisfy 1 <= nev <= n - 2, n is the size of matrix");
184 
185  if(ncv_ < nev_ + 2 || ncv_ > dim_n)
186  throw std::invalid_argument("ncv must satisfy nev + 2 <= ncv <= n, n is the size of matrix");
187  }
188 
198  inline void init(Scalar *init_resid);
199 
207  inline void init();
208 
217  inline int compute(int maxit = 1000, Scalar tol = 1e-10);
218 
222  inline int num_iterations() { return niter; }
223 
227  inline int num_operations() { return nmatop; }
228 
236  inline ComplexVector eigenvalues();
237 
247  inline ComplexMatrix eigenvectors(int nvec);
251  inline ComplexMatrix eigenvectors() { return eigenvectors(nev); }
252 };
253 
254 
255 // Implementations
256 #include "GenEigsSolver_Impl.h"
257 
258 
278 template <typename Scalar = double,
279  int SelectionRule = LARGEST_MAGN,
280  typename OpType = DenseGenRealShiftSolve<double> >
281 class GenEigsRealShiftSolver: public GenEigsSolver<Scalar, SelectionRule, OpType>
282 {
283 private:
284  typedef arma::Col<Scalar> Vector;
285  typedef std::complex<Scalar> Complex;
286  typedef arma::Col<Complex> ComplexVector;
287 
288  Scalar sigma;
289 
290  // First transform back the ritz values, and then sort
291  void sort_ritzpair()
292  {
293  ComplexVector ritz_val_org = Scalar(1.0) / this->ritz_val.head(this->nev) + sigma;
294  this->ritz_val.head(this->nev) = ritz_val_org;
296  }
297 public:
316  GenEigsRealShiftSolver(OpType *op_, int nev_, int ncv_, Scalar sigma_) :
317  GenEigsSolver<Scalar, SelectionRule, OpType>(op_, nev_, ncv_),
318  sigma(sigma_)
319  {
320  this->op->set_shift(sigma);
321  }
322 };
323 
324 #endif // GEN_EIGS_SOLVER_H
GenEigsRealShiftSolver(OpType *op_, int nev_, int ncv_, Scalar sigma_)
int num_iterations()
int num_operations()
ComplexVector eigenvalues()
GenEigsSolver(OpType *op_, int nev_, int ncv_)
int compute(int maxit=1000, Scalar tol=1e-10)
ComplexMatrix eigenvectors()