$darkmode
Eigen-unsupported  5.0.1-dev
PolynomialSolver.h
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 // IWYU pragma: private
14 #include "./InternalHeaderCheck.h"
15 
16 namespace Eigen {
17 
31 template <typename Scalar_, int Deg_>
33  public:
34  EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar_, Deg_ == Dynamic ? Dynamic : Deg_)
35 
36  typedef Scalar_ Scalar;
37  typedef typename NumTraits<Scalar>::Real RealScalar;
38  typedef internal::make_complex_t<Scalar> RootType;
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 
49  public:
50  template <typename OtherPolynomial>
51  inline PolynomialSolverBase(const OtherPolynomial& poly) {
52  setPolynomial(poly());
53  }
54 
55  inline PolynomialSolverBase() {}
56 
57  public:
59  inline const RootsType& roots() const { return m_roots; }
60 
61  public:
72  template <typename Stl_back_insertion_sequence>
73  inline void realRoots(Stl_back_insertion_sequence& bi_seq,
74  const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision()) const {
75  using std::abs;
76  bi_seq.clear();
77  for (Index i = 0; i < m_roots.size(); ++i) {
78  if (abs(m_roots[i].imag()) < absImaginaryThreshold) {
79  bi_seq.push_back(m_roots[i].real());
80  }
81  }
82  }
83 
84  protected:
85  template <typename squaredNormBinaryPredicate>
86  inline const RootType& selectComplexRoot_withRespectToNorm(squaredNormBinaryPredicate& pred) const {
87  Index res = 0;
88  RealScalar norm2 = numext::abs2(m_roots[0]);
89  for (Index i = 1; i < m_roots.size(); ++i) {
90  const RealScalar currNorm2 = numext::abs2(m_roots[i]);
91  if (pred(currNorm2, norm2)) {
92  res = i;
93  norm2 = currNorm2;
94  }
95  }
96  return m_roots[res];
97  }
98 
99  public:
103  inline const RootType& greatestRoot() const {
104  std::greater<RealScalar> greater;
105  return selectComplexRoot_withRespectToNorm(greater);
106  }
107 
111  inline const RootType& smallestRoot() const {
112  std::less<RealScalar> less;
113  return selectComplexRoot_withRespectToNorm(less);
114  }
115 
116  protected:
117  template <typename squaredRealPartBinaryPredicate>
118  inline const RealScalar& selectRealRoot_withRespectToAbsRealPart(
119  squaredRealPartBinaryPredicate& pred, bool& hasArealRoot,
120  const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision()) const {
121  using std::abs;
122  hasArealRoot = false;
123  Index res = 0;
124  RealScalar abs2(0);
125 
126  for (Index i = 0; i < m_roots.size(); ++i) {
127  if (abs(m_roots[i].imag()) <= absImaginaryThreshold) {
128  if (!hasArealRoot) {
129  hasArealRoot = true;
130  res = i;
131  abs2 = m_roots[i].real() * m_roots[i].real();
132  } else {
133  const RealScalar currAbs2 = m_roots[i].real() * m_roots[i].real();
134  if (pred(currAbs2, abs2)) {
135  abs2 = currAbs2;
136  res = i;
137  }
138  }
139  } else if (!hasArealRoot) {
140  if (abs(m_roots[i].imag()) < abs(m_roots[res].imag())) {
141  res = i;
142  }
143  }
144  }
145  return numext::real_ref(m_roots[res]);
146  }
147 
148  template <typename RealPartBinaryPredicate>
149  inline const RealScalar& selectRealRoot_withRespectToRealPart(
150  RealPartBinaryPredicate& pred, bool& hasArealRoot,
151  const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision()) const {
152  using std::abs;
153  hasArealRoot = false;
154  Index res = 0;
155  RealScalar val(0);
156 
157  for (Index i = 0; i < m_roots.size(); ++i) {
158  if (abs(m_roots[i].imag()) <= absImaginaryThreshold) {
159  if (!hasArealRoot) {
160  hasArealRoot = true;
161  res = i;
162  val = m_roots[i].real();
163  } else {
164  const RealScalar curr = m_roots[i].real();
165  if (pred(curr, val)) {
166  val = curr;
167  res = i;
168  }
169  }
170  } else {
171  if (abs(m_roots[i].imag()) < abs(m_roots[res].imag())) {
172  res = i;
173  }
174  }
175  }
176  return numext::real_ref(m_roots[res]);
177  }
178 
179  public:
194  inline const RealScalar& absGreatestRealRoot(
195  bool& hasArealRoot, const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision()) const {
196  std::greater<RealScalar> greater;
197  return selectRealRoot_withRespectToAbsRealPart(greater, hasArealRoot, absImaginaryThreshold);
198  }
199 
214  inline const RealScalar& absSmallestRealRoot(
215  bool& hasArealRoot, const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision()) const {
216  std::less<RealScalar> less;
217  return selectRealRoot_withRespectToAbsRealPart(less, hasArealRoot, absImaginaryThreshold);
218  }
219 
234  inline const RealScalar& greatestRealRoot(
235  bool& hasArealRoot, const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision()) const {
236  std::greater<RealScalar> greater;
237  return selectRealRoot_withRespectToRealPart(greater, hasArealRoot, absImaginaryThreshold);
238  }
239 
254  inline const RealScalar& smallestRealRoot(
255  bool& hasArealRoot, const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision()) const {
256  std::less<RealScalar> less;
257  return selectRealRoot_withRespectToRealPart(less, hasArealRoot, absImaginaryThreshold);
258  }
259 
260  protected:
261  RootsType m_roots;
262 };
263 
264 #define EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES(BASE) \
265  typedef typename BASE::Scalar Scalar; \
266  typedef typename BASE::RealScalar RealScalar; \
267  typedef typename BASE::RootType RootType; \
268  typedef typename BASE::RootsType RootsType;
269 
299 template <typename Scalar_, int Deg_>
300 class PolynomialSolver : public PolynomialSolverBase<Scalar_, Deg_> {
301  public:
302  EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar_, Deg_ == Dynamic ? Dynamic : Deg_)
303 
305  EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES(PS_Base)
306 
308  typedef std::conditional_t<NumTraits<Scalar>::IsComplex, ComplexEigenSolver<CompanionMatrixType>,
310  EigenSolverType;
311  typedef internal::make_complex_t<Scalar_> ComplexScalar;
312 
313  public:
315  template <typename OtherPolynomial>
316  void compute(const OtherPolynomial& poly) {
317  eigen_assert(Scalar(0) != poly[poly.size() - 1]);
318  eigen_assert(poly.size() > 1);
319  if (poly.size() > 2) {
320  internal::companion<Scalar, Deg_> companion(poly);
321  companion.balance();
322  m_eigenSolver.compute(companion.denseMatrix());
323  eigen_assert(m_eigenSolver.info() == Eigen::Success);
324  m_roots = m_eigenSolver.eigenvalues();
325  // cleanup noise in imaginary part of real roots:
326  // if the imaginary part is rather small compared to the real part
327  // and that cancelling the imaginary part yield a smaller evaluation,
328  // then it's safe to keep the real part only.
329  RealScalar coarse_prec = RealScalar(std::pow(4, poly.size() + 1)) * NumTraits<RealScalar>::epsilon();
330  for (Index i = 0; i < m_roots.size(); ++i) {
331  if (internal::isMuchSmallerThan(numext::abs(numext::imag(m_roots[i])), numext::abs(numext::real(m_roots[i])),
332  coarse_prec)) {
333  ComplexScalar as_real_root = ComplexScalar(numext::real(m_roots[i]));
334  if (numext::abs(poly_eval(poly, as_real_root)) <= numext::abs(poly_eval(poly, m_roots[i]))) {
335  m_roots[i] = as_real_root;
336  }
337  }
338  }
339  } else if (poly.size() == 2) {
340  m_roots.resize(1);
341  m_roots[0] = -poly[0] / poly[1];
342  }
343  }
344 
345  public:
346  template <typename OtherPolynomial>
347  inline PolynomialSolver(const OtherPolynomial& poly) {
348  compute(poly);
349  }
350 
351  inline PolynomialSolver() {}
352 
353  protected:
354  using PS_Base::m_roots;
355  EigenSolverType m_eigenSolver;
356 };
357 
358 template <typename Scalar_>
359 class PolynomialSolver<Scalar_, 1> : public PolynomialSolverBase<Scalar_, 1> {
360  public:
361  typedef PolynomialSolverBase<Scalar_, 1> PS_Base;
362  EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES(PS_Base)
363 
364  public:
366  template <typename OtherPolynomial>
367  void compute(const OtherPolynomial& poly) {
368  eigen_assert(poly.size() == 2);
369  eigen_assert(Scalar(0) != poly[1]);
370  m_roots[0] = -poly[0] / poly[1];
371  }
372 
373  public:
374  template <typename OtherPolynomial>
375  inline PolynomialSolver(const OtherPolynomial& poly) {
376  compute(poly);
377  }
378 
379  inline PolynomialSolver() {}
380 
381  protected:
382  using PS_Base::m_roots;
383 };
384 
385 } // end namespace Eigen
386 
387 #endif // EIGEN_POLYNOMIAL_SOLVER_H
const RealScalar & absGreatestRealRoot(bool &hasArealRoot, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
Definition: PolynomialSolver.h:194
const RootType & smallestRoot() const
Definition: PolynomialSolver.h:111
constexpr void resize(Index rows, Index cols)
const RealScalar & greatestRealRoot(bool &hasArealRoot, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
Definition: PolynomialSolver.h:234
Namespace containing all symbols from the Eigen library.
Defined to be inherited by polynomial solvers: it provides convenient methods such as...
Definition: PolynomialSolver.h:32
const RealScalar & smallestRealRoot(bool &hasArealRoot, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
Definition: PolynomialSolver.h:254
const RootsType & roots() const
Definition: PolynomialSolver.h:59
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_abs2_op< typename Derived::Scalar >, const Derived > abs2(const Eigen::ArrayBase< Derived > &x)
T poly_eval(const Polynomials &poly, const T &x)
Definition: PolynomialUtils.h:47
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_imag_op< typename Derived::Scalar >, const Derived > imag(const Eigen::ArrayBase< Derived > &x)
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
const RootType & greatestRoot() const
Definition: PolynomialSolver.h:103
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_real_op< typename Derived::Scalar >, const Derived > real(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_abs_op< typename Derived::Scalar >, const Derived > abs(const Eigen::ArrayBase< Derived > &x)
void realRoots(Stl_back_insertion_sequence &bi_seq, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
Definition: PolynomialSolver.h:73
const int Dynamic
void compute(const OtherPolynomial &poly)
Definition: PolynomialSolver.h:316
A polynomial solver.
Definition: PolynomialSolver.h:300
const RealScalar & absSmallestRealRoot(bool &hasArealRoot, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
Definition: PolynomialSolver.h:214