File indexing completed on 2025-01-18 09:57:06
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef EIGEN_POLYNOMIAL_SOLVER_H
0011 #define EIGEN_POLYNOMIAL_SOLVER_H
0012
0013 namespace Eigen {
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
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
0055 inline const RootsType& roots() const { return m_roots; }
0056
0057 public:
0058
0059
0060
0061
0062
0063
0064
0065
0066
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
0099
0100 inline const RootType& greatestRoot() const
0101 {
0102 std::greater<RealScalar> greater;
0103 return selectComplexRoot_withRespectToNorm( greater );
0104 }
0105
0106
0107
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
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
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
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
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
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
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
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
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
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
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
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
0359
0360
0361
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
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 }
0427
0428 #endif