version 0.4.1
generalizedeigensolver.hh
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2021-2025 The Ikarus Developers ikarus@ibb.uni-stuttgart.de
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
9#pragma once
10
11#include <optional>
12#include <Spectra/MatOp/SparseCholesky.h>
13#include <Spectra/MatOp/SparseGenMatProd.h>
14#include <Spectra/SymEigsSolver.h>
15#include <Spectra/SymGEigsSolver.h>
16#include <utility>
17
18#include <Eigen/Core>
19#include <Eigen/SparseCore>
20
23
24namespace Ikarus {
25
30
31template <EigenValueSolverType SolverType, Concepts::DenseOrSparseEigenMatrix MT>
33{
34};
35
47template <Concepts::DenseOrSparseEigenMatrix MT>
49{
50 using ScalarType = typename MT::Scalar;
51 static constexpr bool isDense = Concepts::EigenMatrix<MT>;
52
53 using MatrixType = MT;
55 std::conditional_t<isDense, Spectra::DenseSymMatProd<ScalarType>, Spectra::SparseSymMatProd<ScalarType>>;
57 std::conditional_t<isDense, Spectra::DenseCholesky<ScalarType>, Spectra::SparseCholesky<ScalarType>>;
58
59 using SolverType = Spectra::SymGEigsSolver<ProductType, CholeskyType, Spectra::GEigsMode::Cholesky>;
60
69 template <typename MATA, typename MATB>
71 GeneralizedSymEigenSolver(MATA&& A, MATB&& B)
72 : nev_(A.rows()),
73 nevsPartition_(static_cast<Eigen::Index>(std::ceil(static_cast<double>(nev_) / 2)),
74 static_cast<Eigen::Index>(nev_ - std::ceil(static_cast<double>(nev_) / 2))),
75 aOP_(std::forward<MATA>(A)),
76 bOP_(std::forward<MATB>(B)),
77 solverSmallest_(aOP_, bOP_, nevsPartition_.first, std::min(nevsPartition_.second * 2, nev_)),
78 solverGreatest_(aOP_, bOP_, nevsPartition_.second, nevsPartition_.second * 2) {
79 if ((A.cols() != B.cols()) or (A.rows() != B.rows()) or (A.cols() != A.rows()))
80 DUNE_THROW(Dune::InvalidStateException,
81 "GeneralizedSymEigenSolver: The passed matrices should have the same size");
82 eigenvalues_.resize(nev_);
83 eigenvectors_.resize(A.rows(), nev_);
84 assert(nevsPartition_.first + nevsPartition_.second == nev_);
85 }
86
95 template <Concepts::FlatAssembler AssemblerA, Concepts::FlatAssembler AssemblerB>
96 GeneralizedSymEigenSolver(std::shared_ptr<AssemblerA> assemblerA, const std::shared_ptr<AssemblerB>& assemblerB)
97 : GeneralizedSymEigenSolver(assemblerA->matrix(), assemblerB->matrix()) {}
98
107 bool compute(Eigen::Index maxit = 1000, ScalarType tolerance = 1e-10) {
108 solverSmallest_.init();
109 solverSmallest_.compute(Spectra::SortRule::SmallestAlge, maxit, tolerance, Spectra::SortRule::SmallestAlge);
110
111 solverGreatest_.init();
112 solverGreatest_.compute(Spectra::SortRule::LargestAlge, maxit, tolerance, Spectra::SortRule::SmallestAlge);
113
114 computed_ = solverSmallest_.info() == Spectra::CompInfo::Successful and
115 solverGreatest_.info() == Spectra::CompInfo::Successful;
116 if (not computed_)
117 return false;
118
119 eigenvalues_.head(nevsPartition_.first) = solverSmallest_.eigenvalues();
120 eigenvectors_.leftCols(nevsPartition_.first) = solverSmallest_.eigenvectors();
121
122 eigenvalues_.tail(nevsPartition_.second) = solverGreatest_.eigenvalues();
123 eigenvectors_.rightCols(nevsPartition_.second) = solverGreatest_.eigenvectors();
124
125 return computed_;
126 }
127
133 auto& eigenvalues() const {
134 assertCompute();
135 return eigenvalues_;
136 }
137
143 auto& eigenvectors() const {
144 assertCompute();
145 return eigenvectors_;
146 }
147
149 Eigen::Index nev() const { return nev_; }
150
151private:
152 Eigen::Index nev_;
153 std::pair<Eigen::Index, Eigen::Index> nevsPartition_;
154 ProductType aOP_;
155 CholeskyType bOP_;
156 SolverType solverSmallest_;
157 SolverType solverGreatest_;
158
159 Eigen::VectorXd eigenvalues_;
160 Eigen::MatrixXd eigenvectors_;
161
162 bool computed_{};
163
164 void assertCompute() const {
165 if (not computed_)
166 DUNE_THROW(Dune::InvalidStateException, "Eigenvalues and -vectors not yet computed, please call compute() first");
167 }
168};
169
177template <Concepts::EigenMatrix MT>
179{
180 using ScalarType = typename MT::Scalar;
181 using MatrixType = MT;
182 using SolverType = Eigen::GeneralizedSelfAdjointEigenSolver<MatrixType>;
183
192 template <typename MATA, typename MATB>
194 GeneralizedSymEigenSolver(MATA&& A, MATB&& B)
195 : matA_(std::forward<MATA>(A)),
196 matB_(std::forward<MATB>(B)),
197 solver_(A.size()) {
198 if ((A.cols() != B.cols()) or (A.rows() != B.rows()) or (A.cols() != A.rows()))
199 DUNE_THROW(Dune::InvalidStateException,
200 "GeneralizedSymEigenSolver: The passed matrices should have the same size");
201 }
202
211 template <Concepts::FlatAssembler AssemblerA, Concepts::FlatAssembler AssemblerB>
212 GeneralizedSymEigenSolver(std::shared_ptr<AssemblerA> assemblerA, std::shared_ptr<AssemblerB> assemblerB)
213 : GeneralizedSymEigenSolver(assemblerA->matrix(), assemblerB->matrix()) {}
214
223 bool compute(int options = Eigen::ComputeEigenvectors) {
224 solver_.compute(matA_, matB_, options);
225 computed_ = true; // SelfAdjointEigenSolver will always be successful if prerequisites are met
226 return computed_;
227 }
228
234 auto& eigenvalues() const {
235 assertCompute();
236 return solver_.eigenvalues();
237 }
238
244 auto& eigenvectors() const {
245 assertCompute();
246 return solver_.eigenvectors();
247 }
248
250 Eigen::Index nev() const { return matA_.rows(); }
251
252private:
253 MatrixType matA_;
254 MatrixType matB_;
255 SolverType solver_;
256 bool computed_{};
257
258 void assertCompute() const {
259 if (not computed_)
260 DUNE_THROW(Dune::InvalidStateException, "Eigenvalues and -vectors not yet computed, please call compute() first");
261 }
262};
263
264namespace Impl {
265 void assertNev(std::optional<Eigen::Index> nev, Eigen::Index nevMax) {
266 if (nev.has_value() and nev.value() > nevMax)
267 DUNE_THROW(Dune::InvalidStateException, "You can not ask for more eigenvalues or eigenvectors than calculated.");
268 }
269} // namespace Impl
270
279template <Concepts::DenseOrSparseEigenMatrix MT>
281{
282 using ScalarType = typename MT::Scalar;
283 static constexpr bool isDense = Concepts::EigenMatrix<MT>;
284
285 using MatrixType = MT;
287 std::conditional_t<isDense, Spectra::DenseSymMatProd<ScalarType>, Spectra::SparseSymMatProd<ScalarType>>;
289 std::conditional_t<isDense, Spectra::DenseCholesky<ScalarType>, Spectra::SparseCholesky<ScalarType>>;
290
291 using SolverType = Spectra::SymGEigsSolver<ProductType, CholeskyType, Spectra::GEigsMode::Cholesky>;
292
301 template <typename MATA, typename MATB>
303 PartialGeneralizedSymEigenSolver(MATA&& A, MATB&& B, Eigen::Index nev)
304 : nev_(nev),
305 aOP_(std::forward<MATA>(A)),
306 bOP_(std::forward<MATB>(B)),
307 solver_(aOP_, bOP_, nev, 2 * nev <= A.cols() ? 2 * nev : A.cols()) {
308 if ((A.cols() != B.cols()) or (A.rows() != B.rows()) or (A.cols() != A.rows()))
309 DUNE_THROW(Dune::InvalidStateException,
310 "PartialGeneralizedSymEigenSolver: The passed matrices should have the same size");
311 }
312
321 template <Concepts::FlatAssembler AssemblerA, Concepts::FlatAssembler AssemblerB>
322 PartialGeneralizedSymEigenSolver(std::shared_ptr<AssemblerA> assemblerA, std::shared_ptr<AssemblerB> assemblerB,
323 Eigen::Index nev)
324 : PartialGeneralizedSymEigenSolver(assemblerA->matrix(), assemblerB->matrix(), nev) {}
325
336 bool compute(Spectra::SortRule selection = Spectra::SortRule::SmallestAlge,
337 Spectra::SortRule sortRule = Spectra::SortRule::SmallestAlge, Eigen::Index maxit = 1000,
338 ScalarType tolerance = 1e-10) {
339 solver_.init();
340 solver_.compute(selection, maxit, tolerance, sortRule);
341
342 computed_ = solver_.info() == Spectra::CompInfo::Successful;
343 return computed_;
344 }
345
351 Eigen::VectorXd eigenvalues() const {
352 assertCompute();
353 return solver_.eigenvalues();
354 }
355
362 auto eigenvectors(std::optional<Eigen::Index> _nev = std::nullopt) const {
363 Impl::assertNev(_nev, nev_);
364 assertCompute();
365 return solver_.eigenvectors(_nev.value_or(nev_));
366 }
367
368 Eigen::Index nev() const { return nev_; }
369
370private:
371 Eigen::Index nev_;
372 ProductType aOP_;
373 CholeskyType bOP_;
374 SolverType solver_;
375
376 bool computed_{};
377
378 void assertCompute() const {
379 if (not computed_)
380 DUNE_THROW(Dune::InvalidStateException, "Eigenvalues and -vectors not yet computed, please call compute() first");
381 }
382};
383
384#ifndef DOXYGEN
385template <Concepts::FlatAssembler AssemblerA, Concepts::FlatAssembler AssemblerB>
386requires(std::same_as<typename AssemblerA::MatrixType, typename AssemblerB::MatrixType>)
387PartialGeneralizedSymEigenSolver(std::shared_ptr<AssemblerA> as1, std::shared_ptr<AssemblerB> as2,
388 Eigen::Index nev) -> PartialGeneralizedSymEigenSolver<typename AssemblerA::MatrixType>;
389
390template <typename MATA, typename MATB>
391requires(Concepts::DenseOrSparseEigenMatrix<std::remove_cvref_t<MATA>> &&
392 std::same_as<std::remove_cvref_t<MATA>, std::remove_cvref_t<MATB>>)
393PartialGeneralizedSymEigenSolver(MATA&&, MATB&&,
394 Eigen::Index) -> PartialGeneralizedSymEigenSolver<std::remove_cvref_t<MATA>>;
395
396#endif
397} // namespace Ikarus
Implementation of the make enum macro.
#define MAKE_ENUM(type,...)
Macro to create an enumeration with a string conversion function.The macro creates an enum class with...
Definition: makeenum.hh:40
Definition: assemblermanipulatorbuildingblocks.hh:22
EigenValueSolverType
A strongly typed enum class representing the type of solver to use for the eigenvalue problem.
Definition: generalizedeigensolver.hh:29
Definition: truncatedconjugategradient.hh:24
Definition: generalizedeigensolver.hh:33
auto & eigenvectors() const
Returns the eigenvectors of the generalized eigenvalue problem.
Definition: generalizedeigensolver.hh:143
std::conditional_t< isDense, Spectra::DenseSymMatProd< ScalarType >, Spectra::SparseSymMatProd< ScalarType > > ProductType
Definition: generalizedeigensolver.hh:55
Eigen::Index nev() const
Returns the number of eigenvalues of the problem.
Definition: generalizedeigensolver.hh:149
std::conditional_t< isDense, Spectra::DenseCholesky< ScalarType >, Spectra::SparseCholesky< ScalarType > > CholeskyType
Definition: generalizedeigensolver.hh:57
typename MT::Scalar ScalarType
Definition: generalizedeigensolver.hh:50
bool compute(Eigen::Index maxit=1000, ScalarType tolerance=1e-10)
Starts the computation of the eigenvalue solver.
Definition: generalizedeigensolver.hh:107
GeneralizedSymEigenSolver(MATA &&A, MATB &&B)
Construct a new GeneralizedSymEigenSolver object.
Definition: generalizedeigensolver.hh:71
Spectra::SymGEigsSolver< ProductType, CholeskyType, Spectra::GEigsMode::Cholesky > SolverType
Definition: generalizedeigensolver.hh:59
GeneralizedSymEigenSolver(std::shared_ptr< AssemblerA > assemblerA, const std::shared_ptr< AssemblerB > &assemblerB)
Construct a new GeneralSymEigenSolver object.
Definition: generalizedeigensolver.hh:96
auto & eigenvalues() const
Returns the eigenvalues of the generalized eigenvalue problem.
Definition: generalizedeigensolver.hh:133
GeneralizedSymEigenSolver(MATA &&A, MATB &&B)
Construct a new GeneralizedSymEigenSolver object.
Definition: generalizedeigensolver.hh:194
Eigen::Index nev() const
Returns the number of eigenvalues of the problem.
Definition: generalizedeigensolver.hh:250
MT MatrixType
Definition: generalizedeigensolver.hh:181
bool compute(int options=Eigen::ComputeEigenvectors)
Starts the computation of the eigenvalue solver.
Definition: generalizedeigensolver.hh:223
GeneralizedSymEigenSolver(std::shared_ptr< AssemblerA > assemblerA, std::shared_ptr< AssemblerB > assemblerB)
Construct a new GeneralSymEigenSolver object.
Definition: generalizedeigensolver.hh:212
auto & eigenvectors() const
Returns the eigenvectors of the generalized eigenvalue problem.
Definition: generalizedeigensolver.hh:244
auto & eigenvalues() const
Returns the eigenvalues of the generalized eigenvalue problem.
Definition: generalizedeigensolver.hh:234
Eigen::GeneralizedSelfAdjointEigenSolver< MatrixType > SolverType
Definition: generalizedeigensolver.hh:182
typename MT::Scalar ScalarType
Definition: generalizedeigensolver.hh:180
This class implements a wrapper to the Spectra generalized eigen solver for square real symmetric mat...
Definition: generalizedeigensolver.hh:281
Spectra::SymGEigsSolver< ProductType, CholeskyType, Spectra::GEigsMode::Cholesky > SolverType
Definition: generalizedeigensolver.hh:291
bool compute(Spectra::SortRule selection=Spectra::SortRule::SmallestAlge, Spectra::SortRule sortRule=Spectra::SortRule::SmallestAlge, Eigen::Index maxit=1000, ScalarType tolerance=1e-10)
Starts the computation of the eigenvalue solver.
Definition: generalizedeigensolver.hh:336
Eigen::Index nev() const
Definition: generalizedeigensolver.hh:368
PartialGeneralizedSymEigenSolver(std::shared_ptr< AssemblerA > assemblerA, std::shared_ptr< AssemblerB > assemblerB, Eigen::Index nev)
Construct a new PartialGeneralizedSymEigenSolver object.
Definition: generalizedeigensolver.hh:322
static constexpr bool isDense
Definition: generalizedeigensolver.hh:283
std::conditional_t< isDense, Spectra::DenseCholesky< ScalarType >, Spectra::SparseCholesky< ScalarType > > CholeskyType
Definition: generalizedeigensolver.hh:289
typename MT::Scalar ScalarType
Definition: generalizedeigensolver.hh:282
MT MatrixType
Definition: generalizedeigensolver.hh:285
Eigen::VectorXd eigenvalues() const
Returns the eigenvalues of the generalized eigenvalue problem.
Definition: generalizedeigensolver.hh:351
std::conditional_t< isDense, Spectra::DenseSymMatProd< ScalarType >, Spectra::SparseSymMatProd< ScalarType > > ProductType
Definition: generalizedeigensolver.hh:287
auto eigenvectors(std::optional< Eigen::Index > _nev=std::nullopt) const
Returns the eigenvectors of the generalized eigenvalue problem.
Definition: generalizedeigensolver.hh:362
PartialGeneralizedSymEigenSolver(MATA &&A, MATB &&B, Eigen::Index nev)
Construct a new PartialGeneralizedSymEigenSolver object.
Definition: generalizedeigensolver.hh:303
Concept defining the requirements for Eigen matrices. This also includes Eigen vectors.
Definition: utils/concepts.hh:373
Concept defining the requirements for sparse or dense Eigen matrices.
Definition: utils/concepts.hh:389
Several concepts.