Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:57:06

0001 // This file is part of Eigen, a lightweight C++ template library
0002 // for linear algebra.
0003 //
0004 // Copyright (C) 2010 Manuel Yguel <manuel.yguel@gmail.com>
0005 //
0006 // This Source Code Form is subject to the terms of the Mozilla
0007 // Public License v. 2.0. If a copy of the MPL was not distributed
0008 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
0009 
0010 #ifndef EIGEN_POLYNOMIAL_SOLVER_H
0011 #define EIGEN_POLYNOMIAL_SOLVER_H
0012 
0013 namespace Eigen { 
0014 
0015 /** \ingroup Polynomials_Module
0016  *  \class PolynomialSolverBase.
0017  *
0018  * \brief Defined to be inherited by polynomial solvers: it provides
0019  * convenient methods such as
0020  *  - real roots,
0021  *  - greatest, smallest complex roots,
0022  *  - real roots with greatest, smallest absolute real value,
0023  *  - greatest, smallest real roots.
0024  *
0025  * It stores the set of roots as a vector of complexes.
0026  *
0027  */
0028 template< typename _Scalar, int _Deg >
0029 class PolynomialSolverBase
0030 {
0031   public:
0032     EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_Deg==Dynamic ? Dynamic : _Deg)
0033 
0034     typedef _Scalar                             Scalar;
0035     typedef typename NumTraits<Scalar>::Real    RealScalar;
0036     typedef std::complex<RealScalar>            RootType;
0037     typedef Matrix<RootType,_Deg,1>             RootsType;
0038 
0039     typedef DenseIndex Index;
0040 
0041   protected:
0042     template< typename OtherPolynomial >
0043     inline void setPolynomial( const OtherPolynomial& poly ){
0044       m_roots.resize(poly.size()-1); }
0045 
0046   public:
0047     template< typename OtherPolynomial >
0048     inline PolynomialSolverBase( const OtherPolynomial& poly ){
0049       setPolynomial( poly() ); }
0050 
0051     inline PolynomialSolverBase(){}
0052 
0053   public:
0054     /** \returns the complex roots of the polynomial */
0055     inline const RootsType& roots() const { return m_roots; }
0056 
0057   public:
0058     /** Clear and fills the back insertion sequence with the real roots of the polynomial
0059      * i.e. the real part of the complex roots that have an imaginary part which
0060      * absolute value is smaller than absImaginaryThreshold.
0061      * absImaginaryThreshold takes the dummy_precision associated
0062      * with the _Scalar template parameter of the PolynomialSolver class as the default value.
0063      *
0064      * \param[out] bi_seq : the back insertion sequence (stl concept)
0065      * \param[in]  absImaginaryThreshold : the maximum bound of the imaginary part of a complex
0066      *  number that is considered as real.
0067      * */
0068     template<typename Stl_back_insertion_sequence>
0069     inline void realRoots( Stl_back_insertion_sequence& bi_seq,
0070         const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
0071     {
0072       using std::abs;
0073       bi_seq.clear();
0074       for(Index i=0; i<m_roots.size(); ++i )
0075       {
0076         if( abs( m_roots[i].imag() ) < absImaginaryThreshold ){
0077           bi_seq.push_back( m_roots[i].real() ); }
0078       }
0079     }
0080 
0081   protected:
0082     template<typename squaredNormBinaryPredicate>
0083     inline const RootType& selectComplexRoot_withRespectToNorm( squaredNormBinaryPredicate& pred ) const
0084     {
0085       Index res=0;
0086       RealScalar norm2 = numext::abs2( m_roots[0] );
0087       for( Index i=1; i<m_roots.size(); ++i )
0088       {
0089         const RealScalar currNorm2 = numext::abs2( m_roots[i] );
0090         if( pred( currNorm2, norm2 ) ){
0091           res=i; norm2=currNorm2; }
0092       }
0093       return m_roots[res];
0094     }
0095 
0096   public:
0097     /**
0098      * \returns the complex root with greatest norm.
0099      */
0100     inline const RootType& greatestRoot() const
0101     {
0102       std::greater<RealScalar> greater;
0103       return selectComplexRoot_withRespectToNorm( greater );
0104     }
0105 
0106     /**
0107      * \returns the complex root with smallest norm.
0108      */
0109     inline const RootType& smallestRoot() const
0110     {
0111       std::less<RealScalar> less;
0112       return selectComplexRoot_withRespectToNorm( less );
0113     }
0114 
0115   protected:
0116     template<typename squaredRealPartBinaryPredicate>
0117     inline const RealScalar& selectRealRoot_withRespectToAbsRealPart(
0118         squaredRealPartBinaryPredicate& pred,
0119         bool& hasArealRoot,
0120         const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
0121     {
0122       using std::abs;
0123       hasArealRoot = false;
0124       Index res=0;
0125       RealScalar abs2(0);
0126 
0127       for( Index i=0; i<m_roots.size(); ++i )
0128       {
0129         if( abs( m_roots[i].imag() ) <= absImaginaryThreshold )
0130         {
0131           if( !hasArealRoot )
0132           {
0133             hasArealRoot = true;
0134             res = i;
0135             abs2 = m_roots[i].real() * m_roots[i].real();
0136           }
0137           else
0138           {
0139             const RealScalar currAbs2 = m_roots[i].real() * m_roots[i].real();
0140             if( pred( currAbs2, abs2 ) )
0141             {
0142               abs2 = currAbs2;
0143               res = i;
0144             }
0145           }
0146         }
0147         else if(!hasArealRoot)
0148         {
0149           if( abs( m_roots[i].imag() ) < abs( m_roots[res].imag() ) ){
0150             res = i;}
0151         }
0152       }
0153       return numext::real_ref(m_roots[res]);
0154     }
0155 
0156 
0157     template<typename RealPartBinaryPredicate>
0158     inline const RealScalar& selectRealRoot_withRespectToRealPart(
0159         RealPartBinaryPredicate& pred,
0160         bool& hasArealRoot,
0161         const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
0162     {
0163       using std::abs;
0164       hasArealRoot = false;
0165       Index res=0;
0166       RealScalar val(0);
0167 
0168       for( Index i=0; i<m_roots.size(); ++i )
0169       {
0170         if( abs( m_roots[i].imag() ) <= absImaginaryThreshold )
0171         {
0172           if( !hasArealRoot )
0173           {
0174             hasArealRoot = true;
0175             res = i;
0176             val = m_roots[i].real();
0177           }
0178           else
0179           {
0180             const RealScalar curr = m_roots[i].real();
0181             if( pred( curr, val ) )
0182             {
0183               val = curr;
0184               res = i;
0185             }
0186           }
0187         }
0188         else
0189         {
0190           if( abs( m_roots[i].imag() ) < abs( m_roots[res].imag() ) ){
0191             res = i; }
0192         }
0193       }
0194       return numext::real_ref(m_roots[res]);
0195     }
0196 
0197   public:
0198     /**
0199      * \returns a real root with greatest absolute magnitude.
0200      * A real root is defined as the real part of a complex root with absolute imaginary
0201      * part smallest than absImaginaryThreshold.
0202      * absImaginaryThreshold takes the dummy_precision associated
0203      * with the _Scalar template parameter of the PolynomialSolver class as the default value.
0204      * If no real root is found the boolean hasArealRoot is set to false and the real part of
0205      * the root with smallest absolute imaginary part is returned instead.
0206      *
0207      * \param[out] hasArealRoot : boolean true if a real root is found according to the
0208      *  absImaginaryThreshold criterion, false otherwise.
0209      * \param[in] absImaginaryThreshold : threshold on the absolute imaginary part to decide
0210      *  whether or not a root is real.
0211      */
0212     inline const RealScalar& absGreatestRealRoot(
0213         bool& hasArealRoot,
0214         const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
0215     {
0216       std::greater<RealScalar> greater;
0217       return selectRealRoot_withRespectToAbsRealPart( greater, hasArealRoot, absImaginaryThreshold );
0218     }
0219 
0220 
0221     /**
0222      * \returns a real root with smallest absolute magnitude.
0223      * A real root is defined as the real part of a complex root with absolute imaginary
0224      * part smallest than absImaginaryThreshold.
0225      * absImaginaryThreshold takes the dummy_precision associated
0226      * with the _Scalar template parameter of the PolynomialSolver class as the default value.
0227      * If no real root is found the boolean hasArealRoot is set to false and the real part of
0228      * the root with smallest absolute imaginary part is returned instead.
0229      *
0230      * \param[out] hasArealRoot : boolean true if a real root is found according to the
0231      *  absImaginaryThreshold criterion, false otherwise.
0232      * \param[in] absImaginaryThreshold : threshold on the absolute imaginary part to decide
0233      *  whether or not a root is real.
0234      */
0235     inline const RealScalar& absSmallestRealRoot(
0236         bool& hasArealRoot,
0237         const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
0238     {
0239       std::less<RealScalar> less;
0240       return selectRealRoot_withRespectToAbsRealPart( less, hasArealRoot, absImaginaryThreshold );
0241     }
0242 
0243 
0244     /**
0245      * \returns the real root with greatest value.
0246      * A real root is defined as the real part of a complex root with absolute imaginary
0247      * part smallest than absImaginaryThreshold.
0248      * absImaginaryThreshold takes the dummy_precision associated
0249      * with the _Scalar template parameter of the PolynomialSolver class as the default value.
0250      * If no real root is found the boolean hasArealRoot is set to false and the real part of
0251      * the root with smallest absolute imaginary part is returned instead.
0252      *
0253      * \param[out] hasArealRoot : boolean true if a real root is found according to the
0254      *  absImaginaryThreshold criterion, false otherwise.
0255      * \param[in] absImaginaryThreshold : threshold on the absolute imaginary part to decide
0256      *  whether or not a root is real.
0257      */
0258     inline const RealScalar& greatestRealRoot(
0259         bool& hasArealRoot,
0260         const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
0261     {
0262       std::greater<RealScalar> greater;
0263       return selectRealRoot_withRespectToRealPart( greater, hasArealRoot, absImaginaryThreshold );
0264     }
0265 
0266 
0267     /**
0268      * \returns the real root with smallest value.
0269      * A real root is defined as the real part of a complex root with absolute imaginary
0270      * part smallest than absImaginaryThreshold.
0271      * absImaginaryThreshold takes the dummy_precision associated
0272      * with the _Scalar template parameter of the PolynomialSolver class as the default value.
0273      * If no real root is found the boolean hasArealRoot is set to false and the real part of
0274      * the root with smallest absolute imaginary part is returned instead.
0275      *
0276      * \param[out] hasArealRoot : boolean true if a real root is found according to the
0277      *  absImaginaryThreshold criterion, false otherwise.
0278      * \param[in] absImaginaryThreshold : threshold on the absolute imaginary part to decide
0279      *  whether or not a root is real.
0280      */
0281     inline const RealScalar& smallestRealRoot(
0282         bool& hasArealRoot,
0283         const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
0284     {
0285       std::less<RealScalar> less;
0286       return selectRealRoot_withRespectToRealPart( less, hasArealRoot, absImaginaryThreshold );
0287     }
0288 
0289   protected:
0290     RootsType               m_roots;
0291 };
0292 
0293 #define EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES( BASE )  \
0294   typedef typename BASE::Scalar                 Scalar;       \
0295   typedef typename BASE::RealScalar             RealScalar;   \
0296   typedef typename BASE::RootType               RootType;     \
0297   typedef typename BASE::RootsType              RootsType;
0298 
0299 
0300 
0301 /** \ingroup Polynomials_Module
0302   *
0303   * \class PolynomialSolver
0304   *
0305   * \brief A polynomial solver
0306   *
0307   * Computes the complex roots of a real polynomial.
0308   *
0309   * \param _Scalar the scalar type, i.e., the type of the polynomial coefficients
0310   * \param _Deg the degree of the polynomial, can be a compile time value or Dynamic.
0311   *             Notice that the number of polynomial coefficients is _Deg+1.
0312   *
0313   * This class implements a polynomial solver and provides convenient methods such as
0314   * - real roots,
0315   * - greatest, smallest complex roots,
0316   * - real roots with greatest, smallest absolute real value.
0317   * - greatest, smallest real roots.
0318   *
0319   * WARNING: this polynomial solver is experimental, part of the unsupported Eigen modules.
0320   *
0321   *
0322   * Currently a QR algorithm is used to compute the eigenvalues of the companion matrix of
0323   * the polynomial to compute its roots.
0324   * This supposes that the complex moduli of the roots are all distinct: e.g. there should
0325   * be no multiple roots or conjugate roots for instance.
0326   * With 32bit (float) floating types this problem shows up frequently.
0327   * However, almost always, correct accuracy is reached even in these cases for 64bit
0328   * (double) floating types and small polynomial degree (<20).
0329   */
0330 template<typename _Scalar, int _Deg>
0331 class PolynomialSolver : public PolynomialSolverBase<_Scalar,_Deg>
0332 {
0333   public:
0334     EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(_Scalar,_Deg==Dynamic ? Dynamic : _Deg)
0335 
0336     typedef PolynomialSolverBase<_Scalar,_Deg>    PS_Base;
0337     EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES( PS_Base )
0338 
0339     typedef Matrix<Scalar,_Deg,_Deg>                 CompanionMatrixType;
0340     typedef typename internal::conditional<NumTraits<Scalar>::IsComplex,
0341                                           ComplexEigenSolver<CompanionMatrixType>,
0342                                           EigenSolver<CompanionMatrixType> >::type EigenSolverType;
0343     typedef typename internal::conditional<NumTraits<Scalar>::IsComplex, Scalar, std::complex<Scalar> >::type ComplexScalar;
0344 
0345   public:
0346     /** Computes the complex roots of a new polynomial. */
0347     template< typename OtherPolynomial >
0348     void compute( const OtherPolynomial& poly )
0349     {
0350       eigen_assert( Scalar(0) != poly[poly.size()-1] );
0351       eigen_assert( poly.size() > 1 );
0352       if(poly.size() >  2 )
0353       {
0354         internal::companion<Scalar,_Deg> companion( poly );
0355         companion.balance();
0356         m_eigenSolver.compute( companion.denseMatrix() );
0357         m_roots = m_eigenSolver.eigenvalues();
0358         // cleanup noise in imaginary part of real roots:
0359         // if the imaginary part is rather small compared to the real part
0360         // and that cancelling the imaginary part yield a smaller evaluation,
0361         // then it's safe to keep the real part only.
0362         RealScalar coarse_prec = RealScalar(std::pow(4,poly.size()+1))*NumTraits<RealScalar>::epsilon();
0363         for(Index i = 0; i<m_roots.size(); ++i)
0364         {
0365           if( internal::isMuchSmallerThan(numext::abs(numext::imag(m_roots[i])),
0366                                           numext::abs(numext::real(m_roots[i])),
0367                                           coarse_prec) )
0368           {
0369             ComplexScalar as_real_root = ComplexScalar(numext::real(m_roots[i]));
0370             if(    numext::abs(poly_eval(poly, as_real_root))
0371                 <= numext::abs(poly_eval(poly, m_roots[i])))
0372             {
0373               m_roots[i] = as_real_root;
0374             }
0375           }
0376         }
0377       }
0378       else if(poly.size () == 2)
0379       {
0380         m_roots.resize(1);
0381         m_roots[0] = -poly[0]/poly[1];
0382       }
0383     }
0384 
0385   public:
0386     template< typename OtherPolynomial >
0387     inline PolynomialSolver( const OtherPolynomial& poly ){
0388       compute( poly ); }
0389 
0390     inline PolynomialSolver(){}
0391 
0392   protected:
0393     using                   PS_Base::m_roots;
0394     EigenSolverType         m_eigenSolver;
0395 };
0396 
0397 
0398 template< typename _Scalar >
0399 class PolynomialSolver<_Scalar,1> : public PolynomialSolverBase<_Scalar,1>
0400 {
0401   public:
0402     typedef PolynomialSolverBase<_Scalar,1>    PS_Base;
0403     EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES( PS_Base )
0404 
0405   public:
0406     /** Computes the complex roots of a new polynomial. */
0407     template< typename OtherPolynomial >
0408     void compute( const OtherPolynomial& poly )
0409     {
0410       eigen_assert( poly.size() == 2 );
0411       eigen_assert( Scalar(0) != poly[1] );
0412       m_roots[0] = -poly[0]/poly[1];
0413     }
0414 
0415   public:
0416     template< typename OtherPolynomial >
0417     inline PolynomialSolver( const OtherPolynomial& poly ){
0418       compute( poly ); }
0419 
0420     inline PolynomialSolver(){}
0421 
0422   protected:
0423     using                   PS_Base::m_roots;
0424 };
0425 
0426 } // end namespace Eigen
0427 
0428 #endif // EIGEN_POLYNOMIAL_SOLVER_H