yixuan / spectra

A header-only C++ library for large scale eigenvalue problems
https://spectralib.org
Mozilla Public License 2.0
745 stars 131 forks source link

Spectra doesn't accept non-literal data types anymore #150

Closed jdbancal closed 1 year ago

jdbancal commented 1 year ago

I observe the following error after updating some code to Spectra version 1:

In file included from ../external/spectra/include/Spectra/LinAlg/Lanczos.h:15,
                 from ../external/spectra/include/Spectra/SymEigsBase.h:25,
                 from ../external/spectra/include/Spectra/SymEigsSolver.h:12,
                 from gem.hpp:11,
                 from sgem.cpp:1:
../external/spectra/include/Spectra/LinAlg/Arnoldi.h: In instantiation of ‘class Spectra::Arnoldi<mpfr::mpreal, Spectra::ArnoldiOp<mpfr::mpreal, Spectra::SparseSymMatProd<mpfr::mpreal>, Spectra::IdentityBOp> >’:
../external/spectra/include/Spectra/LinAlg/Lanczos.h:27:7:   required from ‘class Spectra::Lanczos<mpfr::mpreal, Spectra::ArnoldiOp<mpfr::mpreal, Spectra::SparseSymMatProd<mpfr::mpreal>, Spectra::IdentityBOp> >’
../external/spectra/include/Spectra/SymEigsBase.h:76:19:   required from ‘class Spectra::SymEigsBase<Spectra::SparseSymMatProd<mpfr::mpreal>, Spectra::IdentityBOp>’
../external/spectra/include/Spectra/SymEigsSolver.h:134:7:   required from ‘class Spectra::SymEigsSolver<Spectra::SparseSymMatProd<mpfr::mpreal> >’
sgem.cpp:5171:86:   required from here
../external/spectra/include/Spectra/LinAlg/Arnoldi.h:44:29: error: the type ‘const mpfr::mpreal’ of ‘constexpr’ variable ‘Spectra::Arnoldi<mpfr::mpreal, Spectra::ArnoldiOp<mpfr::mpreal, Spectra::SparseSymMatProd<mpfr::mpreal>, Spectra::IdentityBOp> >::m_near_0’ is not literal
     static constexpr Scalar m_near_0 = TypeTraits<Scalar>::min() * Scalar(10);
                             ^~~~~~~~
In file included from ../external/eigen/unsupported/Eigen/MPRealSupport:16,
                 from gem.hpp:7,
                 from sgem.cpp:1:
../external/mpfrc++/mpreal.h:150:7: note: ‘mpfr::mpreal’ is not literal because:
 class mpreal {
       ^~~~~~
../external/mpfrc++/mpreal.h:150:7: note:   ‘mpfr::mpreal’ has a non-trivial destructor
In file included from ../external/spectra/include/Spectra/LinAlg/Lanczos.h:15,
                 from ../external/spectra/include/Spectra/SymEigsBase.h:25,
                 from ../external/spectra/include/Spectra/SymEigsSolver.h:12,
                 from gem.hpp:11,
                 from sgem.cpp:1:

The problem seems to be that the scalar type mpreal, which relies on the external mpfr library, and thus requires some initialization and fine-tuning to work efficiently, admits a class destructor mpreal::~mpreal(). It would be great if the latest version of Spectra was able to make abstraction of the scalar type that it acts on like the previous versions.

The code at hand is the following:

Spectra::SparseSymMatProd<mpreal> op(matrixR);
Spectra::SymEigsSolver< Spectra::SparseSymMatProd<mpreal> > eigs(op, nbEigenvalues, ncv);
eigs.init();
mpreal tolerance(pow(10,-mpfr::bits2digits(mpfr::mpreal::get_default_prec())));
int nconv = eigs.compute(Spectra::SortRule::LargestMagn, maxIter, tolerance, Spectra::SortRule::LargestMagn);

The following code compiled and worked very well on Spectra 0.9.0 (prior to following the upgrading instructions in https://spectralib.org/upgrade.html)

Spectra::SparseSymMatProd<mpreal> op(matrixR);
Spectra::SymEigsSolver< mpreal, Spectra::LARGEST_MAGN, Spectra::SparseSymMatProd<mpreal> > eigs(&op, nbEigenvalues, ncv);
eigs.init();
mpreal tolerance(pow(10,-mpfr::bits2digits(mpfr::mpreal::get_default_prec())));
int nconv = eigs.compute(maxIter, tolerance, Spectra::LARGEST_MAGN);
yixuan commented 1 year ago

This should have been fixed in https://github.com/yixuan/spectra/commit/c8de5eb5e8a6725e3334c37546febc9b77393677. Can you do a quick test?

jdbancal commented 1 year ago

Yep, it compiles again, looks good. Thank you!