Eigen-unsupported  5.0.1-dev+284dcc12
 
Loading...
Searching...
No Matches
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
16namespace Eigen {
17
31template <typename Scalar_, int Deg_>
32class PolynomialSolverBase {
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;
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
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
299template <typename Scalar_, int Deg_>
300class PolynomialSolver : public PolynomialSolverBase<Scalar_, Deg_> {
301 public:
302 EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar_, Deg_ == Dynamic ? Dynamic : Deg_)
303
304 typedef PolynomialSolverBase<Scalar_, Deg_> PS_Base;
305 EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES(PS_Base)
306
307 typedef Matrix<Scalar, Deg_, Deg_> CompanionMatrixType;
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
358template <typename Scalar_>
359class 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
constexpr void resize(Index rows, Index cols)
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 RealScalar & absGreatestRealRoot(bool &hasArealRoot, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
Definition PolynomialSolver.h:194
const RealScalar & absSmallestRealRoot(bool &hasArealRoot, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
Definition PolynomialSolver.h:214
void realRoots(Stl_back_insertion_sequence &bi_seq, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
Definition PolynomialSolver.h:73
const RootType & greatestRoot() const
Definition PolynomialSolver.h:103
const RealScalar & greatestRealRoot(bool &hasArealRoot, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
Definition PolynomialSolver.h:234
const RootType & smallestRoot() const
Definition PolynomialSolver.h:111
const RootsType & roots() const
Definition PolynomialSolver.h:59
A polynomial solver.
Definition PolynomialSolver.h:300
void compute(const OtherPolynomial &poly)
Definition PolynomialSolver.h:316
T poly_eval(const Polynomials &poly, const T &x)
Definition PolynomialUtils.h:47
Namespace containing all symbols from the Eigen library.
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)
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_abs2_op< typename Derived::Scalar >, const Derived > abs2(const Eigen::ArrayBase< Derived > &x)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_imag_op< typename Derived::Scalar >, const Derived > imag(const Eigen::ArrayBase< Derived > &x)
const int Dynamic