Spectra  1.0.1
Header-only C++ Library for Large Scale Eigenvalue Problems
JDSymEigsBase.h
1 // Copyright (C) 2020 Netherlands eScience Center <J.Wehner@esciencecenter.nl>
2 //
3 // This Source Code Form is subject to the terms of the Mozilla
4 // Public License v. 2.0. If a copy of the MPL was not distributed
5 // with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
6 
7 #ifndef SPECTRA_JD_SYM_EIGS_BASE_H
8 #define SPECTRA_JD_SYM_EIGS_BASE_H
9 
10 #include <Eigen/Core>
11 #include <vector> // std::vector
12 #include <cmath> // std::abs, std::pow
13 #include <algorithm> // std::min
14 #include <stdexcept> // std::invalid_argument
15 #include <iostream>
16 
17 #include "Util/SelectionRule.h"
18 #include "Util/CompInfo.h"
19 #include "LinAlg/SearchSpace.h"
20 #include "LinAlg/RitzPairs.h"
21 
22 namespace Spectra {
23 
33 template <typename Derived, typename OpType>
35 {
36 protected:
37  using Index = Eigen::Index;
38  using Scalar = typename OpType::Scalar;
39  using Matrix = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
40  using Vector = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
41 
42  const OpType& m_matrix_operator; // object to conduct matrix operation,
43  // e.g. matrix-vector product
44  Index niter_ = 0;
45  const Index m_number_eigenvalues; // number of eigenvalues requested
46  Index m_max_search_space_size;
47  Index m_initial_search_space_size;
48  Index m_correction_size; // how many correction vectors are added in each iteration
49  RitzPairs<Scalar> m_ritz_pairs; // Ritz eigen pair structure
50  SearchSpace<Scalar> m_search_space; // search space
51 
52 private:
53  CompInfo m_info = CompInfo::NotComputed; // status of the computation
54 
55  void check_argument() const
56  {
57  if (m_number_eigenvalues < 1 || m_number_eigenvalues > m_matrix_operator.cols() - 1)
58  throw std::invalid_argument("nev must satisfy 1 <= nev <= n - 1, n is the size of matrix");
59  }
60 
61  void initialize()
62  {
63  // TODO better input validation and checks
64  if (m_matrix_operator.cols() < m_max_search_space_size)
65  {
66  m_max_search_space_size = m_matrix_operator.cols();
67  }
68  if (m_matrix_operator.cols() < m_initial_search_space_size + m_correction_size)
69  {
70  m_initial_search_space_size = m_matrix_operator.cols() / 3;
71  m_correction_size = m_matrix_operator.cols() / 3;
72  }
73  }
74 
75 public:
76  JDSymEigsBase(OpType& op, Index nev, Index nvec_init, Index nvec_max) :
77  m_matrix_operator(op),
78  m_number_eigenvalues(nev),
79  m_max_search_space_size(nvec_max < op.rows() ? nvec_max : 10 * m_number_eigenvalues),
80  m_initial_search_space_size(nvec_init < op.rows() ? nvec_init : 2 * m_number_eigenvalues),
81  m_correction_size(m_number_eigenvalues)
82  {
83  check_argument();
84  initialize();
85  }
86 
87  JDSymEigsBase(OpType& op, Index nev) :
88  JDSymEigsBase(op, nev, 2 * nev, 10 * nev) {}
89 
93  void set_max_search_space_size(Index max_search_space_size)
94  {
95  m_max_search_space_size = max_search_space_size;
96  }
100  void set_correction_size(Index correction_size)
101  {
102  m_correction_size = correction_size;
103  }
104 
108  void set_initial_search_space_size(Index initial_search_space_size)
109  {
110  m_initial_search_space_size = initial_search_space_size;
111  }
112 
116  virtual ~JDSymEigsBase() {}
117 
122  CompInfo info() const { return m_info; }
123 
127  Index num_iterations() const { return niter_; }
128 
129  Vector eigenvalues() const { return m_ritz_pairs.ritz_values().head(m_number_eigenvalues); }
130 
131  Matrix eigenvectors() const { return m_ritz_pairs.ritz_vectors().leftCols(m_number_eigenvalues); }
132 
133  Index compute(SortRule selection = SortRule::LargestMagn, Index maxit = 100,
134  Scalar tol = 100 * Eigen::NumTraits<Scalar>::dummy_precision())
135  {
136  Derived& derived = static_cast<Derived&>(*this);
137  Matrix intial_space = derived.setup_initial_search_space(selection);
138  return compute_with_guess(intial_space, selection, maxit, tol);
139  }
140 
141  Index compute_with_guess(const Eigen::Ref<const Matrix>& initial_space,
142  SortRule selection = SortRule::LargestMagn,
143  Index maxit = 100,
144  Scalar tol = 100 * Eigen::NumTraits<Scalar>::dummy_precision())
145 
146  {
147  m_search_space.initialize_search_space(initial_space);
148  niter_ = 0;
149  for (niter_ = 0; niter_ < maxit; niter_++)
150  {
151  bool do_restart = (m_search_space.size() > m_max_search_space_size);
152 
153  if (do_restart)
154  {
155  m_search_space.restart(m_ritz_pairs, m_initial_search_space_size);
156  }
157 
158  m_search_space.update_operator_basis_product(m_matrix_operator);
159 
160  Eigen::ComputationInfo small_problem_info = m_ritz_pairs.compute_eigen_pairs(m_search_space);
161  if (small_problem_info != Eigen::ComputationInfo::Success)
162  {
163  m_info = CompInfo::NumericalIssue;
164  break;
165  }
166  m_ritz_pairs.sort(selection);
167 
168  bool converged = m_ritz_pairs.check_convergence(tol, m_number_eigenvalues);
169  if (converged)
170  {
171  m_info = CompInfo::Successful;
172  break;
173  }
174  else if (niter_ == maxit - 1)
175  {
176  m_info = CompInfo::NotConverging;
177  break;
178  }
179  Derived& derived = static_cast<Derived&>(*this);
180  Matrix corr_vect = derived.calculate_correction_vector();
181 
182  m_search_space.extend_basis(corr_vect);
183  }
184  return (m_ritz_pairs.converged_eigenvalues()).template cast<Index>().head(m_number_eigenvalues).sum();
185  }
186 };
187 
188 } // namespace Spectra
189 
190 #endif // SPECTRA_JD_SYM_EIGS_BASE_H
CompInfo info() const
void set_correction_size(Index correction_size)
Index num_iterations() const
void set_initial_search_space_size(Index initial_search_space_size)
void set_max_search_space_size(Index max_search_space_size)
Definition: JDSymEigsBase.h:93
CompInfo
Definition: CompInfo.h:18
@ Successful
Computation was successful.