Spectra  1.0.1
Header-only C++ Library for Large Scale Eigenvalue Problems
SymGEigsShiftSolver.h
1 // Copyright (C) 2020-2022 Yixuan Qiu <yixuan.qiu@cos.name>
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_SYM_GEIGS_SHIFT_SOLVER_H
8 #define SPECTRA_SYM_GEIGS_SHIFT_SOLVER_H
9 
10 #include <utility> // std::move
11 #include "SymEigsBase.h"
12 #include "Util/GEigsMode.h"
13 #include "MatOp/internal/SymGEigsShiftInvertOp.h"
14 #include "MatOp/internal/SymGEigsBucklingOp.h"
15 #include "MatOp/internal/SymGEigsCayleyOp.h"
16 
17 namespace Spectra {
18 
41 
42 // Empty class template
43 template <typename OpType, typename BOpType, GEigsMode Mode>
45 {};
46 
144 
145 // Partial specialization for mode = GEigsMode::ShiftInvert
146 template <typename OpType, typename BOpType>
147 class SymGEigsShiftSolver<OpType, BOpType, GEigsMode::ShiftInvert> :
148  public SymEigsBase<SymGEigsShiftInvertOp<OpType, BOpType>, BOpType>
149 {
150 private:
151  using Scalar = typename OpType::Scalar;
152  using Index = Eigen::Index;
153  using Array = Eigen::Array<Scalar, Eigen::Dynamic, 1>;
154 
155  using ModeMatOp = SymGEigsShiftInvertOp<OpType, BOpType>;
157  using Base::m_nev;
158  using Base::m_ritz_val;
159 
160  const Scalar m_sigma;
161 
162  // Set shift and forward
163  static ModeMatOp set_shift_and_move(ModeMatOp&& op, const Scalar& sigma)
164  {
165  op.set_shift(sigma);
166  return std::move(op);
167  }
168 
169  // First transform back the Ritz values, and then sort
170  void sort_ritzpair(SortRule sort_rule) override
171  {
172  // The eigenvalues we get from the iteration is nu = 1 / (lambda - sigma)
173  // So the eigenvalues of the original problem is lambda = 1 / nu + sigma
174  m_ritz_val.head(m_nev).array() = Scalar(1) / m_ritz_val.head(m_nev).array() + m_sigma;
175  Base::sort_ritzpair(sort_rule);
176  }
177 
178 public:
200  SymGEigsShiftSolver(OpType& op, BOpType& Bop, Index nev, Index ncv, const Scalar& sigma) :
201  Base(set_shift_and_move(ModeMatOp(op, Bop), sigma), Bop, nev, ncv),
202  m_sigma(sigma)
203  {}
204 };
205 
304 
305 // Partial specialization for mode = GEigsMode::Buckling
306 template <typename OpType, typename BOpType>
307 class SymGEigsShiftSolver<OpType, BOpType, GEigsMode::Buckling> :
308  public SymEigsBase<SymGEigsBucklingOp<OpType, BOpType>, BOpType>
309 {
310 private:
311  using Scalar = typename OpType::Scalar;
312  using Index = Eigen::Index;
313  using Array = Eigen::Array<Scalar, Eigen::Dynamic, 1>;
314 
315  using ModeMatOp = SymGEigsBucklingOp<OpType, BOpType>;
317  using Base::m_nev;
318  using Base::m_ritz_val;
319 
320  const Scalar m_sigma;
321 
322  // Set shift and forward
323  static ModeMatOp set_shift_and_move(ModeMatOp&& op, const Scalar& sigma)
324  {
325  if (sigma == Scalar(0))
326  throw std::invalid_argument("SymGEigsShiftSolver: sigma cannot be zero in the buckling mode");
327  op.set_shift(sigma);
328  return std::move(op);
329  }
330 
331  // First transform back the Ritz values, and then sort
332  void sort_ritzpair(SortRule sort_rule) override
333  {
334  // The eigenvalues we get from the iteration is nu = lambda / (lambda - sigma)
335  // So the eigenvalues of the original problem is lambda = sigma * nu / (nu - 1)
336  m_ritz_val.head(m_nev).array() = m_sigma * m_ritz_val.head(m_nev).array() /
337  (m_ritz_val.head(m_nev).array() - Scalar(1));
338  Base::sort_ritzpair(sort_rule);
339  }
340 
341 public:
363  SymGEigsShiftSolver(OpType& op, BOpType& Bop, Index nev, Index ncv, const Scalar& sigma) :
364  Base(set_shift_and_move(ModeMatOp(op, Bop), sigma), Bop, nev, ncv),
365  m_sigma(sigma)
366  {}
367 };
368 
396 
397 // Partial specialization for mode = GEigsMode::Cayley
398 template <typename OpType, typename BOpType>
399 class SymGEigsShiftSolver<OpType, BOpType, GEigsMode::Cayley> :
400  public SymEigsBase<SymGEigsCayleyOp<OpType, BOpType>, BOpType>
401 {
402 private:
403  using Scalar = typename OpType::Scalar;
404  using Index = Eigen::Index;
405  using Array = Eigen::Array<Scalar, Eigen::Dynamic, 1>;
406 
407  using ModeMatOp = SymGEigsCayleyOp<OpType, BOpType>;
409  using Base::m_nev;
410  using Base::m_ritz_val;
411 
412  const Scalar m_sigma;
413 
414  // Set shift and forward
415  static ModeMatOp set_shift_and_move(ModeMatOp&& op, const Scalar& sigma)
416  {
417  if (sigma == Scalar(0))
418  throw std::invalid_argument("SymGEigsShiftSolver: sigma cannot be zero in the Cayley mode");
419  op.set_shift(sigma);
420  return std::move(op);
421  }
422 
423  // First transform back the Ritz values, and then sort
424  void sort_ritzpair(SortRule sort_rule) override
425  {
426  // The eigenvalues we get from the iteration is nu = (lambda + sigma) / (lambda - sigma)
427  // So the eigenvalues of the original problem is lambda = sigma * (nu + 1) / (nu - 1)
428  m_ritz_val.head(m_nev).array() = m_sigma * (m_ritz_val.head(m_nev).array() + Scalar(1)) /
429  (m_ritz_val.head(m_nev).array() - Scalar(1));
430  Base::sort_ritzpair(sort_rule);
431  }
432 
433 public:
455  SymGEigsShiftSolver(OpType& op, BOpType& Bop, Index nev, Index ncv, const Scalar& sigma) :
456  Base(set_shift_and_move(ModeMatOp(op, Bop), sigma), Bop, nev, ncv),
457  m_sigma(sigma)
458  {}
459 };
460 
461 } // namespace Spectra
462 
463 #endif // SPECTRA_SYM_GEIGS_SHIFT_SOLVER_H
SymGEigsShiftSolver(OpType &op, BOpType &Bop, Index nev, Index ncv, const Scalar &sigma)
SymGEigsShiftSolver(OpType &op, BOpType &Bop, Index nev, Index ncv, const Scalar &sigma)
SymGEigsShiftSolver(OpType &op, BOpType &Bop, Index nev, Index ncv, const Scalar &sigma)
@ Buckling
Buckling mode for generalized eigenvalue solver.
@ Cayley
Cayley transformation mode for generalized eigenvalue solver.
@ ShiftInvert
Shift-and-invert mode for generalized eigenvalue solver.