// Copyright (C) 2016-2019 Yixuan Qiu // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at https://mozilla.org/MPL/2.0/. #ifndef SELECTION_RULE_H #define SELECTION_RULE_H #include // std::vector #include // std::abs #include // std::sort #include // std::complex #include // std::pair #include // std::invalid_argument namespace Spectra { /// /// \defgroup Enumerations /// /// Enumeration types for the selection rule of eigenvalues. /// /// /// \ingroup Enumerations /// /// The enumeration of selection rules of desired eigenvalues. /// enum SELECT_EIGENVALUE { LARGEST_MAGN = 0, ///< Select eigenvalues with largest magnitude. Magnitude ///< means the absolute value for real numbers and norm for ///< complex numbers. Applies to both symmetric and general ///< eigen solvers. LARGEST_REAL, ///< Select eigenvalues with largest real part. Only for general eigen solvers. LARGEST_IMAG, ///< Select eigenvalues with largest imaginary part (in magnitude). Only for general eigen solvers. LARGEST_ALGE, ///< Select eigenvalues with largest algebraic value, considering ///< any negative sign. Only for symmetric eigen solvers. SMALLEST_MAGN, ///< Select eigenvalues with smallest magnitude. Applies to both symmetric and general ///< eigen solvers. SMALLEST_REAL, ///< Select eigenvalues with smallest real part. Only for general eigen solvers. SMALLEST_IMAG, ///< Select eigenvalues with smallest imaginary part (in magnitude). Only for general eigen solvers. SMALLEST_ALGE, ///< Select eigenvalues with smallest algebraic value. Only for symmetric eigen solvers. BOTH_ENDS ///< Select eigenvalues half from each end of the spectrum. When ///< `nev` is odd, compute more from the high end. Only for symmetric eigen solvers. }; /// /// \ingroup Enumerations /// /// The enumeration of selection rules of desired eigenvalues. Alias for `SELECT_EIGENVALUE`. /// enum SELECT_EIGENVALUE_ALIAS { WHICH_LM = 0, ///< Alias for `LARGEST_MAGN` WHICH_LR, ///< Alias for `LARGEST_REAL` WHICH_LI, ///< Alias for `LARGEST_IMAG` WHICH_LA, ///< Alias for `LARGEST_ALGE` WHICH_SM, ///< Alias for `SMALLEST_MAGN` WHICH_SR, ///< Alias for `SMALLEST_REAL` WHICH_SI, ///< Alias for `SMALLEST_IMAG` WHICH_SA, ///< Alias for `SMALLEST_ALGE` WHICH_BE ///< Alias for `BOTH_ENDS` }; /// \cond // Get the element type of a "scalar" // ElemType => double // ElemType< std::complex > => double template class ElemType { public: typedef T type; }; template class ElemType< std::complex > { public: typedef T type; }; // When comparing eigenvalues, we first calculate the "target" // to sort. For example, if we want to choose the eigenvalues with // largest magnitude, the target will be -abs(x). // The minus sign is due to the fact that std::sort() sorts in ascending order. // Default target: throw an exception template class SortingTarget { public: static typename ElemType::type get(const Scalar& val) { using std::abs; throw std::invalid_argument("incompatible selection rule"); return -abs(val); } }; // Specialization for LARGEST_MAGN // This covers [float, double, complex] x [LARGEST_MAGN] template class SortingTarget { public: static typename ElemType::type get(const Scalar& val) { using std::abs; return -abs(val); } }; // Specialization for LARGEST_REAL // This covers [complex] x [LARGEST_REAL] template class SortingTarget, LARGEST_REAL> { public: static RealType get(const std::complex& val) { return -val.real(); } }; // Specialization for LARGEST_IMAG // This covers [complex] x [LARGEST_IMAG] template class SortingTarget, LARGEST_IMAG> { public: static RealType get(const std::complex& val) { using std::abs; return -abs(val.imag()); } }; // Specialization for LARGEST_ALGE // This covers [float, double] x [LARGEST_ALGE] template class SortingTarget { public: static Scalar get(const Scalar& val) { return -val; } }; // Here BOTH_ENDS is the same as LARGEST_ALGE, but // we need some additional steps, which are done in // SymEigsSolver.h => retrieve_ritzpair(). // There we move the smallest values to the proper locations. template class SortingTarget { public: static Scalar get(const Scalar& val) { return -val; } }; // Specialization for SMALLEST_MAGN // This covers [float, double, complex] x [SMALLEST_MAGN] template class SortingTarget { public: static typename ElemType::type get(const Scalar& val) { using std::abs; return abs(val); } }; // Specialization for SMALLEST_REAL // This covers [complex] x [SMALLEST_REAL] template class SortingTarget, SMALLEST_REAL> { public: static RealType get(const std::complex& val) { return val.real(); } }; // Specialization for SMALLEST_IMAG // This covers [complex] x [SMALLEST_IMAG] template class SortingTarget, SMALLEST_IMAG> { public: static RealType get(const std::complex& val) { using std::abs; return abs(val.imag()); } }; // Specialization for SMALLEST_ALGE // This covers [float, double] x [SMALLEST_ALGE] template class SortingTarget { public: static Scalar get(const Scalar& val) { return val; } }; // Sort eigenvalues and return the order index template class PairComparator { public: bool operator() (const PairType& v1, const PairType& v2) { return v1.first < v2.first; } }; template class SortEigenvalue { private: typedef typename ElemType::type TargetType; // Type of the sorting target, will be // a floating number type, e.g. "double" typedef std::pair PairType; // Type of the sorting pair, including // the sorting target and the index std::vector pair_sort; public: SortEigenvalue(const T* start, int size) : pair_sort(size) { for(int i = 0; i < size; i++) { pair_sort[i].first = SortingTarget::get(start[i]); pair_sort[i].second = i; } PairComparator comp; std::sort(pair_sort.begin(), pair_sort.end(), comp); } std::vector index() { std::vector ind(pair_sort.size()); for(unsigned int i = 0; i < ind.size(); i++) ind[i] = pair_sort[i].second; return ind; } }; /// \endcond } // namespace Spectra #endif // SELECTION_RULE_H