Spectra 1.1.0
Header-only C++ Library for Large Scale Eigenvalue Problems
Loading...
Searching...
No Matches
SymGEigsShiftSolver.h
1// Copyright (C) 2020-2025 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 "HermEigsBase.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
17namespace Spectra {
18
41
42// Empty class template
43template <typename OpType, typename BOpType, GEigsMode Mode>
46
144
145// Partial specialization for mode = GEigsMode::ShiftInvert
146template <typename OpType, typename BOpType>
147class SymGEigsShiftSolver<OpType, BOpType, GEigsMode::ShiftInvert> :
148 public HermEigsBase<SymGEigsShiftInvertOp<OpType, BOpType>, BOpType>
149{
150private:
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
178public:
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
306template <typename OpType, typename BOpType>
307class SymGEigsShiftSolver<OpType, BOpType, GEigsMode::Buckling> :
308 public HermEigsBase<SymGEigsBucklingOp<OpType, BOpType>, BOpType>
309{
310private:
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
341public:
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
398template <typename OpType, typename BOpType>
399class SymGEigsShiftSolver<OpType, BOpType, GEigsMode::Cayley> :
400 public HermEigsBase<SymGEigsCayleyOp<OpType, BOpType>, BOpType>
401{
402private:
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
433public:
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.
Definition GEigsMode.h:22
@ Cayley
Cayley transformation mode for generalized eigenvalue solver.
Definition GEigsMode.h:23
@ ShiftInvert
Shift-and-invert mode for generalized eigenvalue solver.
Definition GEigsMode.h:21