From 34bb893f35b25f9e52be67b6a3828035aa0424d0 Mon Sep 17 00:00:00 2001 From: Felix Schindler <felix.schindler@wwu.de> Date: Tue, 14 Nov 2017 18:38:39 +0100 Subject: [PATCH] [eigen-solver.fmatrix] refactor to match new design --- dune/xt/la/eigen-solver/fmatrix.hh | 234 ++++++++++++++++------------- 1 file changed, 128 insertions(+), 106 deletions(-) diff --git a/dune/xt/la/eigen-solver/fmatrix.hh b/dune/xt/la/eigen-solver/fmatrix.hh index a99ae8c51..c74563575 100644 --- a/dune/xt/la/eigen-solver/fmatrix.hh +++ b/dune/xt/la/eigen-solver/fmatrix.hh @@ -13,7 +13,12 @@ #include <algorithm> #include <functional> +#include <dune/common/typetraits.hh> + #include <dune/xt/common/fmatrix.hh> +#include <dune/xt/common/matrix.hh> +#include <dune/xt/common/numeric_cast.hh> +#include <dune/xt/la/container/conversion.hh> #include <dune/xt/la/container/eigen/dense.hh> #include <dune/xt/la/solver.hh> #include <dune/xt/la/eigen-solver.hh> @@ -27,148 +32,165 @@ namespace XT { namespace LA { -template <class S, int dimRange> -class FieldMatrixEigenSolverTraits -{ -public: - typedef Dune::FieldMatrix<S, dimRange, dimRange> MatrixType; - typedef typename Dune::FieldTraits<S>::real_type RealType; - typedef typename std::complex<RealType> ComplexType; - typedef typename Dune::FieldVector<RealType, dimRange> RealVectorType; - typedef typename Dune::FieldVector<ComplexType, dimRange> ComplexVectorType; - typedef typename Dune::FieldMatrix<RealType, dimRange, dimRange> RealMatrixType; - typedef typename Dune::FieldMatrix<ComplexType, dimRange, dimRange> ComplexMatrixType; - typedef EigenSolver<MatrixType> derived_type; -}; +#if HAVE_LAPACKE || HAVE_EIGEN -template <class S, int dimRange> -class EigenSolver<Dune::FieldMatrix<S, dimRange, dimRange>> - : public EigenSolverBase<FieldMatrixEigenSolverTraits<S, dimRange>> -{ - typedef EigenSolverBase<FieldMatrixEigenSolverTraits<S, dimRange>> BaseType; +template <class K, int SIZE> +class EigenSolverOptions<Dune::FieldMatrix<K, SIZE, SIZE>> +{ public: - using typename BaseType::MatrixType; - using typename BaseType::ComplexType; - using typename BaseType::ComplexVectorType; - using typename BaseType::RealMatrixType; - - EigenSolver(const MatrixType& matrix, const bool disable_checks = false) - : BaseType(matrix, disable_checks) - { - } - static std::vector<std::string> types() { return { #if HAVE_LAPACKE - "lapacke", + "lapacke" +#if HAVE_EIGEN + , #endif +#endif // HAVE_LAPACKE #if HAVE_EIGEN "eigen" -#endif -#if 0 - , - "qrhouseholder" #endif }; } static Common::Configuration options(const std::string type = "") { - const std::string tp = !type.empty() ? type : types()[0]; - internal::SolverUtils::check_given(tp, types()); - Common::Configuration default_options( - {"type", "check_for_inf_nan", "check_evs_are_real", "check_evs_are_positive", "check_eigenvectors_are_real"}, - {tp.c_str(), "1", "0", "0", "0"}); - return default_options; + const std::string actual_type = type.empty() ? types()[0] : type; + internal::ensure_eigen_solver_type(actual_type, types()); + Common::Configuration opts = internal::default_eigen_solver_options(); + opts["type"] = actual_type; + return opts; } +}; // class EigenSolverOptions<Dune::FieldMatrix<K, SIZE, SIZE>> + + +template <class K, int SIZE> +class EigenSolverOptions<Dune::XT::Common::FieldMatrix<K, SIZE, SIZE>> + : public EigenSolverOptions<Dune::FieldMatrix<K, SIZE, SIZE>> +{ +}; + + +template <class K, int SIZE> +class EigenSolver<Dune::FieldMatrix<K, SIZE, SIZE>> + : public internal::EigenSolverBase<Dune::FieldMatrix<K, SIZE, SIZE>, + K, + Dune::FieldMatrix<XT::Common::real_t<K>, SIZE, SIZE>, + Dune::FieldMatrix<XT::Common::complex_t<K>, SIZE, SIZE>> +{ + using BaseType = internal::EigenSolverBase<Dune::FieldMatrix<K, SIZE, SIZE>, + K, + Dune::FieldMatrix<XT::Common::real_t<K>, SIZE, SIZE>, + Dune::FieldMatrix<XT::Common::complex_t<K>, SIZE, SIZE>>; - virtual void get_eigenvalues(std::vector<ComplexType>& evs, const std::string& type) const override final +public: + using typename BaseType::MatrixType; + using typename BaseType::RealType; + + template <class... Args> + explicit EigenSolver(Args&&... args) + : BaseType(std::forward<Args>(args)...) { - if (false) - ; // empty statement to be able to use else if -#if HAVE_LAPACKE - else if (type == "lapacke") - evs = internal::compute_all_eigenvalues_using_lapacke(matrix_); -#endif // HAVE_LAPACKE -#if HAVE_EIGEN - else if (type == "eigen") { - XT::LA::EigenDenseMatrix<S> eigenmatrix(dimRange, dimRange); - for (size_t rr = 0; rr < dimRange; ++rr) - for (size_t cc = 0; cc < dimRange; ++cc) - eigenmatrix.set_entry(rr, cc, matrix_[rr][cc]); - evs = internal::compute_all_eigenvalues_using_eigen(eigenmatrix.backend()); - } -#endif -#if 0 - else if (type == "qrhouseholder") - evs = internal::compute_all_eigenvalues_using_qrhouseholder(matrix_); -#endif - else - DUNE_THROW(Common::Exceptions::internal_error, - "Given type '" << type << "' is not supported, although it was reported by types()!"); - } // ... get_eigenvalues(...) + } - virtual void get_eigenvectors(std::vector<ComplexVectorType>& evs, const std::string& type) const override final +protected: + void compute() const override final { - evs.resize(dimRange); - if (false) - ; // empty statement to be able to use else if + const auto type = options_.template get<std::string>("type"); #if HAVE_LAPACKE - else if (type == "lapacke") - internal::compute_all_eigenvectors_using_lapacke(matrix_, evs, evs[0][0]); -#endif + if (type == "lapacke") { + if (options_.template get<bool>("compute_eigenvalues")) + eigenvalues_ = std::make_unique<std::vector<XT::Common::complex_t<RealType>>>( + internal::compute_all_eigenvalues_using_lapacke(matrix_)); + if (options_.template get<bool>("compute_eigenvectors")) { + eigenvectors_ = std::make_unique<Dune::FieldMatrix<XT::Common::complex_t<K>, SIZE, SIZE>>(); + internal::compute_all_eigenvectors_using_lapacke(matrix_, *eigenvectors_); + } + } else +#endif // HAVE_LAPACKE #if HAVE_EIGEN - else if (type == "eigen") { - XT::LA::EigenDenseMatrix<S> eigenmatrix(dimRange, dimRange); - for (size_t rr = 0; rr < dimRange; ++rr) - for (size_t cc = 0; cc < dimRange; ++cc) - eigenmatrix.set_entry(rr, cc, matrix_[rr][cc]); - auto eigen_eigvecs = internal::compute_all_eigenvectors_using_eigen(eigenmatrix.backend()); - for (size_t rr = 0; rr < dimRange; ++rr) - for (size_t cc = 0; cc < dimRange; ++cc) - evs[rr][cc] = eigen_eigvecs[rr].get_entry(cc); - } -#endif -#if 0 - else if (type == "qrhouseholder") - internal::compute_all_eigenvectors_using_qrhouseholder(matrix_, evs, evs[0][0]); -#endif - else + if (type == "eigen") { + if (options_.template get<bool>("compute_eigenvalues") && options_.template get<bool>("compute_eigenvectors")) { + eigenvalues_ = std::make_unique<std::vector<XT::Common::complex_t<RealType>>>(SIZE); + EigenDenseMatrix<K> tmp_matrix(matrix_); + EigenDenseMatrix<Common::complex_t<K>> tmp_eigenvectors(matrix_); + internal::compute_all_eigenvalues_and_vectors_using_eigen( + tmp_matrix.backend(), *eigenvalues_, tmp_eigenvectors.backend()); + eigenvectors_ = std::make_unique<Dune::FieldMatrix<XT::Common::complex_t<K>, SIZE, SIZE>>( + convert_to<Dune::FieldMatrix<XT::Common::complex_t<K>, SIZE, SIZE>>(tmp_eigenvectors)); + } else { + if (options_.template get<bool>("compute_eigenvalues")) + eigenvalues_ = std::make_unique<std::vector<XT::Common::complex_t<RealType>>>( + internal::compute_all_eigenvalues_using_eigen(EigenDenseMatrix<K>(matrix_).backend())); + if (options_.template get<bool>("compute_eigenvectors")) { + eigenvectors_ = std::make_unique<Dune::FieldMatrix<XT::Common::complex_t<K>, SIZE, SIZE>>( + convert_to<Dune::FieldMatrix<XT::Common::complex_t<K>, SIZE, SIZE>>( + EigenDenseMatrix<XT::Common::complex_t<K>>( + internal::compute_all_eigenvectors_using_eigen(EigenDenseMatrix<K>(matrix_).backend())))); + } + } + } else +#endif // HAVE_EIGEN DUNE_THROW(Common::Exceptions::internal_error, - "Given type '" << type << "' is not supported, although it was reported by types()!"); - } // ... get_eigenvectors(...) + "Given type '" << type << "' is none of EigenSolverOptions<Dune::FieldMatrix<K, ROWS, " + "COLS>>::types(), and internal::EigenSolverBase promised to check this!" + << "\n\nThese are the available types:\n\n" + << EigenSolverOptions<MatrixType>::types()); + } //... compute(...) - using BaseType::real_eigenvectors; - - virtual std::shared_ptr<RealMatrixType> real_eigenvectors_as_matrix(const Common::Configuration& opts) const override - { - const auto evs = real_eigenvectors(opts); - auto ret = std::make_shared<RealMatrixType>(); - for (size_t ii = 0; ii < dimRange; ++ii) - for (size_t jj = 0; jj < dimRange; ++jj) - (*ret)[ii][jj] = evs[jj][ii]; - return ret; - } // ... real_eigenvectors_as_matrix(...) - -private: using BaseType::matrix_; -}; // class EigenSolver<FieldMatrix<S>> + using BaseType::options_; + using BaseType::eigenvalues_; + using BaseType::eigenvectors_; +}; // class EigenSolver<EigenDenseMatrix<...>> -template <class S, int dimRange> -class EigenSolver<Dune::XT::Common::FieldMatrix<S, dimRange, dimRange>> - : public EigenSolver<Dune::FieldMatrix<S, dimRange, dimRange>> + +template <class K, int SIZE> +class EigenSolver<Dune::XT::Common::FieldMatrix<K, SIZE, SIZE>> : public EigenSolver<Dune::FieldMatrix<K, SIZE, SIZE>> { template <class... Args> EigenSolver(Args&&... args) - : EigenSolver<Dune::FieldMatrix<S, dimRange, dimRange>>(std::forward<Args>(args)...) + : EigenSolver<Dune::FieldMatrix<K, SIZE, SIZE>>(std::forward<Args>(args)...) { } }; +#else // HAVE_LAPACKE || HAVE_EIGEN + + +template <class K, int SIZE> +class EigenSolverOptions<Dune::FieldMatrix<K, SIZE, SIZE>> +{ + static_assert(AlwaysFalse<K>::value, "You are missing the required backends!"); +}; + + +template <class K, int SIZE> +class EigenSolverOptions<Dune::XT::Common::FieldMatrix<K, SIZE, SIZE>> +{ + static_assert(AlwaysFalse<K>::value, "You are missing the required backends!"); +}; + + +template <class K, int SIZE> +class EigenSolver<Dune::FieldMatrix<K, SIZE, SIZE>> +{ + static_assert(AlwaysFalse<K>::value, "You are missing the required backends!"); +}; + + +template <class K, int SIZE> +class EigenSolver<Dune::XT::Common::FieldMatrix<K, SIZE, SIZE>> +{ + static_assert(AlwaysFalse<K>::value, "You are missing the required backends!"); +}; + + +#endif // HAVE_LAPACKE || HAVE_EIGEN + } // namespace LA } // namespace XT } // namespace Dune -- GitLab