PolynomialSolver.h
Go to the documentation of this file.
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2010 Manuel Yguel <manuel.yguel@gmail.com>
5 //
6 // This Source Code Form is subject to the terms of the Mozilla
7 // Public License v. 2.0. If a copy of the MPL was not distributed
8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 
10 #ifndef EIGEN_POLYNOMIAL_SOLVER_H
11 #define EIGEN_POLYNOMIAL_SOLVER_H
12 
13 #include "./InternalHeaderCheck.h"
14 
15 namespace Eigen {
16 
30 template< typename Scalar_, int Deg_ >
32 {
33  public:
35 
36  typedef Scalar_ Scalar;
37  typedef typename NumTraits<Scalar>::Real RealScalar;
38  typedef std::complex<RealScalar> RootType;
39  typedef Matrix<RootType,Deg_,1> RootsType;
40 
41  typedef DenseIndex Index;
42 
43  protected:
44  template< typename OtherPolynomial >
45  inline void setPolynomial( const OtherPolynomial& poly ){
46  m_roots.resize(poly.size()-1); }
47 
48  public:
49  template< typename OtherPolynomial >
50  inline PolynomialSolverBase( const OtherPolynomial& poly ){
51  setPolynomial( poly() ); }
52 
54 
55  public:
57  inline const RootsType& roots() const { return m_roots; }
58 
59  public:
70  template<typename Stl_back_insertion_sequence>
71  inline void realRoots( Stl_back_insertion_sequence& bi_seq,
72  const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
73  {
74  using std::abs;
75  bi_seq.clear();
76  for(Index i=0; i<m_roots.size(); ++i )
77  {
78  if( abs( m_roots[i].imag() ) < absImaginaryThreshold ){
79  bi_seq.push_back( m_roots[i].real() ); }
80  }
81  }
82 
83  protected:
84  template<typename squaredNormBinaryPredicate>
85  inline const RootType& selectComplexRoot_withRespectToNorm( squaredNormBinaryPredicate& pred ) const
86  {
87  Index res=0;
88  RealScalar norm2 = numext::abs2( m_roots[0] );
89  for( Index i=1; i<m_roots.size(); ++i )
90  {
91  const RealScalar currNorm2 = numext::abs2( m_roots[i] );
92  if( pred( currNorm2, norm2 ) ){
93  res=i; norm2=currNorm2; }
94  }
95  return m_roots[res];
96  }
97 
98  public:
102  inline const RootType& greatestRoot() const
103  {
104  std::greater<RealScalar> greater;
105  return selectComplexRoot_withRespectToNorm( greater );
106  }
107 
111  inline const RootType& smallestRoot() const
112  {
113  std::less<RealScalar> less;
115  }
116 
117  protected:
118  template<typename squaredRealPartBinaryPredicate>
120  squaredRealPartBinaryPredicate& pred,
121  bool& hasArealRoot,
122  const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
123  {
124  using std::abs;
125  hasArealRoot = false;
126  Index res=0;
127  RealScalar abs2(0);
128 
129  for( Index i=0; i<m_roots.size(); ++i )
130  {
131  if( abs( m_roots[i].imag() ) <= absImaginaryThreshold )
132  {
133  if( !hasArealRoot )
134  {
135  hasArealRoot = true;
136  res = i;
137  abs2 = m_roots[i].real() * m_roots[i].real();
138  }
139  else
140  {
141  const RealScalar currAbs2 = m_roots[i].real() * m_roots[i].real();
142  if( pred( currAbs2, abs2 ) )
143  {
144  abs2 = currAbs2;
145  res = i;
146  }
147  }
148  }
149  else if(!hasArealRoot)
150  {
151  if( abs( m_roots[i].imag() ) < abs( m_roots[res].imag() ) ){
152  res = i;}
153  }
154  }
155  return numext::real_ref(m_roots[res]);
156  }
157 
158 
159  template<typename RealPartBinaryPredicate>
161  RealPartBinaryPredicate& pred,
162  bool& hasArealRoot,
163  const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
164  {
165  using std::abs;
166  hasArealRoot = false;
167  Index res=0;
168  RealScalar val(0);
169 
170  for( Index i=0; i<m_roots.size(); ++i )
171  {
172  if( abs( m_roots[i].imag() ) <= absImaginaryThreshold )
173  {
174  if( !hasArealRoot )
175  {
176  hasArealRoot = true;
177  res = i;
178  val = m_roots[i].real();
179  }
180  else
181  {
182  const RealScalar curr = m_roots[i].real();
183  if( pred( curr, val ) )
184  {
185  val = curr;
186  res = i;
187  }
188  }
189  }
190  else
191  {
192  if( abs( m_roots[i].imag() ) < abs( m_roots[res].imag() ) ){
193  res = i; }
194  }
195  }
196  return numext::real_ref(m_roots[res]);
197  }
198 
199  public:
215  bool& hasArealRoot,
216  const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
217  {
218  std::greater<RealScalar> greater;
219  return selectRealRoot_withRespectToAbsRealPart( greater, hasArealRoot, absImaginaryThreshold );
220  }
221 
222 
238  bool& hasArealRoot,
239  const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
240  {
241  std::less<RealScalar> less;
242  return selectRealRoot_withRespectToAbsRealPart( less, hasArealRoot, absImaginaryThreshold );
243  }
244 
245 
261  bool& hasArealRoot,
262  const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
263  {
264  std::greater<RealScalar> greater;
265  return selectRealRoot_withRespectToRealPart( greater, hasArealRoot, absImaginaryThreshold );
266  }
267 
268 
284  bool& hasArealRoot,
285  const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
286  {
287  std::less<RealScalar> less;
288  return selectRealRoot_withRespectToRealPart( less, hasArealRoot, absImaginaryThreshold );
289  }
290 
291  protected:
293 };
294 
295 #define EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES( BASE ) \
296  typedef typename BASE::Scalar Scalar; \
297  typedef typename BASE::RealScalar RealScalar; \
298  typedef typename BASE::RootType RootType; \
299  typedef typename BASE::RootsType RootsType;
300 
301 
302 
332 template<typename Scalar_, int Deg_>
333 class PolynomialSolver : public PolynomialSolverBase<Scalar_,Deg_>
334 {
335  public:
337 
338  typedef PolynomialSolverBase<Scalar_,Deg_> PS_Base;
340 
341  typedef Matrix<Scalar,Deg_,Deg_> CompanionMatrixType;
342  typedef std::conditional_t<NumTraits<Scalar>::IsComplex,
345  typedef std::conditional_t<NumTraits<Scalar>::IsComplex, Scalar, std::complex<Scalar> > ComplexScalar;
346 
347  public:
349  template< typename OtherPolynomial >
350  void compute( const OtherPolynomial& poly )
351  {
352  eigen_assert( Scalar(0) != poly[poly.size()-1] );
353  eigen_assert( poly.size() > 1 );
354  if(poly.size() > 2 )
355  {
356  internal::companion<Scalar,Deg_> companion( poly );
357  companion.balance();
358  m_eigenSolver.compute( companion.denseMatrix() );
359  m_roots = m_eigenSolver.eigenvalues();
360  // cleanup noise in imaginary part of real roots:
361  // if the imaginary part is rather small compared to the real part
362  // and that cancelling the imaginary part yield a smaller evaluation,
363  // then it's safe to keep the real part only.
364  RealScalar coarse_prec = RealScalar(std::pow(4,poly.size()+1))*NumTraits<RealScalar>::epsilon();
365  for(Index i = 0; i<m_roots.size(); ++i)
366  {
369  coarse_prec) )
370  {
372  if( numext::abs(poly_eval(poly, as_real_root))
373  <= numext::abs(poly_eval(poly, m_roots[i])))
374  {
375  m_roots[i] = as_real_root;
376  }
377  }
378  }
379  }
380  else if(poly.size () == 2)
381  {
382  m_roots.resize(1);
383  m_roots[0] = -poly[0]/poly[1];
384  }
385  }
386 
387  public:
388  template< typename OtherPolynomial >
389  inline PolynomialSolver( const OtherPolynomial& poly ){
390  compute( poly ); }
391 
392  inline PolynomialSolver(){}
393 
394  protected:
395  using PS_Base::m_roots;
397 };
398 
399 
400 template< typename Scalar_ >
401 class PolynomialSolver<Scalar_,1> : public PolynomialSolverBase<Scalar_,1>
402 {
403  public:
406 
407  public:
409  template< typename OtherPolynomial >
410  void compute( const OtherPolynomial& poly )
411  {
412  eigen_assert( poly.size() == 2 );
413  eigen_assert( Scalar(0) != poly[1] );
414  m_roots[0] = -poly[0]/poly[1];
415  }
416 
417  public:
418  template< typename OtherPolynomial >
419  inline PolynomialSolver( const OtherPolynomial& poly ){
420  compute( poly ); }
421 
422  inline PolynomialSolver(){}
423 
424  protected:
425  using PS_Base::m_roots;
426 };
427 
428 } // end namespace Eigen
429 
430 #endif // EIGEN_POLYNOMIAL_SOLVER_H
int i
#define eigen_assert(x)
#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar, Size)
cout<< "Here is the matrix m:"<< endl<< m<< endl;Matrix< ptrdiff_t, 3, 1 > res
#define EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES(BASE)
constexpr void resize(Index rows, Index cols)
Defined to be inherited by polynomial solvers: it provides convenient methods such as.
void setPolynomial(const OtherPolynomial &poly)
const RealScalar & selectRealRoot_withRespectToRealPart(RealPartBinaryPredicate &pred, bool &hasArealRoot, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
PolynomialSolverBase(const OtherPolynomial &poly)
const RootType & greatestRoot() const
std::complex< RealScalar > RootType
const RootType & smallestRoot() const
const RootType & selectComplexRoot_withRespectToNorm(squaredNormBinaryPredicate &pred) const
const RealScalar & greatestRealRoot(bool &hasArealRoot, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
const RealScalar & selectRealRoot_withRespectToAbsRealPart(squaredRealPartBinaryPredicate &pred, bool &hasArealRoot, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
void realRoots(Stl_back_insertion_sequence &bi_seq, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
const RealScalar & smallestRealRoot(bool &hasArealRoot, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
NumTraits< Scalar >::Real RealScalar
const RealScalar & absSmallestRealRoot(bool &hasArealRoot, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
const RealScalar & absGreatestRealRoot(bool &hasArealRoot, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
const RootsType & roots() const
void compute(const OtherPolynomial &poly)
PolynomialSolverBase< Scalar_, 1 > PS_Base
PolynomialSolver(const OtherPolynomial &poly)
A polynomial solver.
EigenSolverType m_eigenSolver
void compute(const OtherPolynomial &poly)
PolynomialSolver(const OtherPolynomial &poly)
std::conditional_t< NumTraits< Scalar >::IsComplex, ComplexEigenSolver< CompanionMatrixType >, EigenSolver< CompanionMatrixType > > EigenSolverType
std::conditional_t< NumTraits< Scalar >::IsComplex, Scalar, std::complex< Scalar > > ComplexScalar
T poly_eval(const Polynomials &poly, const T &x)
bool isMuchSmallerThan(const Scalar &x, const OtherScalar &y, const typename NumTraits< Scalar >::Real &precision=NumTraits< Scalar >::dummy_precision())
bool abs2(bool x)
internal::add_const_on_value_type_t< EIGEN_MATHFUNC_RETVAL(real_ref, Scalar) > real_ref(const Scalar &x)
EIGEN_ALWAYS_INLINE std::enable_if_t< NumTraits< T >::IsSigned||NumTraits< T >::IsComplex, typename NumTraits< T >::Real > abs(const T &x)
: TensorContractionSycl.h, provides various tensor contraction kernel for SYCL backend
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_imag_op< typename Derived::Scalar >, const Derived > imag(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_abs2_op< typename Derived::Scalar >, const Derived > abs2(const Eigen::ArrayBase< Derived > &x)
Eigen::AutoDiffScalar< EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(internal::remove_all_t< DerType >, typename internal::traits< internal::remove_all_t< DerType >>::Scalar, product) > pow(const Eigen::AutoDiffScalar< DerType > &x, const typename internal::traits< internal::remove_all_t< DerType >>::Scalar &y)
EIGEN_DEFAULT_DENSE_INDEX_TYPE DenseIndex
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_real_op< typename Derived::Scalar >, const Derived > real(const Eigen::ArrayBase< Derived > &x)
const int Dynamic
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_abs_op< typename Derived::Scalar >, const Derived > abs(const Eigen::ArrayBase< Derived > &x)
adouble abs(const adouble &x)
Definition: AdolcForward:74
const adouble & real(const adouble &x)
Definition: AdolcForward:72
adouble imag(const adouble &)
Definition: AdolcForward:73