11#ifndef EIGEN_POLYNOMIAL_SOLVER_H
12#define EIGEN_POLYNOMIAL_SOLVER_H
15#include "./InternalHeaderCheck.h"
32template <
typename Scalar_,
int Deg_>
33class PolynomialSolverBase {
35 EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar_, Deg_ == Dynamic ? Dynamic : Deg_)
37 typedef Scalar_ Scalar;
39 typedef internal::make_complex_t<Scalar> RootType;
42 typedef DenseIndex Index;
45 template <
typename OtherPolynomial>
46 inline void setPolynomial(
const OtherPolynomial& poly) {
47 m_roots.
resize(poly.size() - 1);
51 template <
typename OtherPolynomial>
52 inline PolynomialSolverBase(
const OtherPolynomial& poly) {
53 setPolynomial(poly());
56 inline PolynomialSolverBase() {}
60 inline const RootsType&
roots()
const {
return m_roots; }
73 template <
typename Stl_back_insertion_sequence>
74 inline void realRoots(Stl_back_insertion_sequence& bi_seq,
78 for (Index i = 0; i < m_roots.size(); ++i) {
79 if (abs(m_roots[i].imag()) < absImaginaryThreshold) {
80 bi_seq.push_back(m_roots[i].real());
86 template <
typename Predicate>
87 inline const RootType& selectComplexRoot_withRespectToNorm(Predicate& pred)
const {
89 RealScalar norm2 = numext::abs2(m_roots[0]);
90 for (Index i = 1; i < m_roots.size(); ++i) {
91 const RealScalar currNorm2 = numext::abs2(m_roots[i]);
92 if (pred(currNorm2, norm2)) {
105 std::greater<RealScalar> greater;
106 return selectComplexRoot_withRespectToNorm(greater);
113 std::less<RealScalar> less;
114 return selectComplexRoot_withRespectToNorm(less);
118 template <
typename Predicate>
119 inline const RealScalar& selectRealRoot_withRespectToAbsRealPart(
120 Predicate& pred,
bool& hasArealRoot,
123 hasArealRoot =
false;
127 for (Index i = 0; i < m_roots.size(); ++i) {
128 if (abs(m_roots[i].imag()) <= absImaginaryThreshold) {
132 val = abs(m_roots[i].real());
134 const RealScalar curr = abs(m_roots[i].real());
135 if (pred(curr, val)) {
140 }
else if (!hasArealRoot) {
141 if (abs(m_roots[i].imag()) < abs(m_roots[res].imag())) {
146 return numext::real_ref(m_roots[res]);
149 template <
typename Predicate>
150 inline const RealScalar& selectRealRoot_withRespectToRealPart(
151 Predicate& pred,
bool& hasArealRoot,
152 const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision())
const {
154 hasArealRoot =
false;
158 for (Index i = 0; i < m_roots.size(); ++i) {
159 if (abs(m_roots[i].imag()) <= absImaginaryThreshold) {
163 val = m_roots[i].real();
165 const RealScalar curr = m_roots[i].real();
166 if (pred(curr, val)) {
172 if (abs(m_roots[i].imag()) < abs(m_roots[res].imag())) {
177 return numext::real_ref(m_roots[res]);
197 std::greater<RealScalar> greater;
198 return selectRealRoot_withRespectToAbsRealPart(greater, hasArealRoot, absImaginaryThreshold);
217 std::less<RealScalar> less;
218 return selectRealRoot_withRespectToAbsRealPart(less, hasArealRoot, absImaginaryThreshold);
237 std::greater<RealScalar> greater;
238 return selectRealRoot_withRespectToRealPart(greater, hasArealRoot, absImaginaryThreshold);
257 std::less<RealScalar> less;
258 return selectRealRoot_withRespectToRealPart(less, hasArealRoot, absImaginaryThreshold);
265#define EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES(BASE) \
266 typedef typename BASE::Scalar Scalar; \
267 typedef typename BASE::RealScalar RealScalar; \
268 typedef typename BASE::RootType RootType; \
269 typedef typename BASE::RootsType RootsType;
299template <
typename Scalar_,
int Deg_>
300class PolynomialSolver :
public PolynomialSolverBase<Scalar_, Deg_> {
302 EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar_, Deg_ == Dynamic ? Dynamic : Deg_)
304 typedef PolynomialSolverBase<Scalar_, Deg_> PS_Base;
305 EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES(PS_Base)
311 typedef internal::make_complex_t<Scalar_> ComplexScalar;
315 template <
typename OtherPolynomial>
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);
322 m_eigenSolver.compute(companion.denseMatrix());
324 m_roots = m_eigenSolver.eigenvalues();
326 const RealScalar scale = poly.realView().cwiseAbs().maxCoeff();
327 const auto scaledPoly = (poly / scale).eval();
330 }
else if (poly.size() == 2) {
332 m_roots[0] = -poly[0] / poly[1];
337 template <
typename OtherPolynomial>
342 inline PolynomialSolver() {}
349 template <
typename OtherPolynomial>
350 static RealScalar evaluate(
const OtherPolynomial& poly,
const RootType& z, RootType& value, RootType& derivative,
352 const Index degree = poly.size() - 1;
353 value = RootType(poly[degree]);
354 derivative = RootType(0);
356 for (Index k = degree - 1; k >= 0; --k) {
357 derivative = derivative * z + value;
358 value = value * z + RootType(poly[k]);
360 return RealScalar(0);
362 const RealScalar absz = numext::abs(z);
363 RealScalar mu = numext::abs(value) / RealScalar(2);
364 for (Index k = degree - 1; k >= 0; --k) {
365 derivative = derivative * z + value;
366 value = value * z + RootType(poly[k]);
367 mu = mu * absz + numext::abs(value);
369 const RealScalar errorScale = numext::sqrt(RealScalar(2)) * NumTraits<RealScalar>::epsilon();
370 return (RealScalar(2) * errorScale) * mu - errorScale * numext::abs(value);
381 template <
typename OtherPolynomial>
383 const Index n = m_roots.size();
388 for (Index i = 0; i < n; ++i) {
390 if (numext::imag(m_roots[i]) == RealScalar(0)) {
391 const RealScalar perturbation = eps * numext::abs(m_roots[i]);
392 m_roots[i] += RootType(0, i % 2 == 0 ? perturbation : -perturbation);
397 RootType value, derivative;
398 for (
int sweep = 0; sweep < maxSweeps; ++sweep) {
400 for (Index i = 0; i < n; ++i) {
401 if (!active[i])
continue;
402 const RootType z = m_roots[i];
405 const bool testResidual = sweep > 0;
406 const RealScalar bound = evaluate(poly, z, value, derivative, testResidual);
407 if ((testResidual && !(numext::abs(value) > bound)) || !(numext::isfinite)(bound) ||
408 derivative == RootType(0)) {
412 const RootType newton = value / derivative;
413 if (!(numext::abs(newton) > eps * numext::abs(z))) {
417 RootType repulsion(0);
418 for (Index j = 0; j < n; ++j) {
419 const RootType gap = z - m_roots[j];
420 if (j != i && gap != RootType(0)) repulsion += RootType(1) / gap;
422 const RootType denominator = RootType(1) - newton * repulsion;
423 const RootType refined = z - (denominator == RootType(0) ? newton : RootType(newton / denominator));
424 if ((numext::isfinite)(numext::abs(refined))) {
425 m_roots[i] = refined;
434 for (Index i = 0; i < n; ++i) {
435 if (!active[i])
continue;
436 RootType initialValue;
437 evaluate(poly, m_roots[i], value, derivative,
false);
438 evaluate(poly, m_eigenSolver.eigenvalues()[i], initialValue, derivative,
false);
439 if (!(numext::abs(value) <= numext::abs(initialValue))) m_roots[i] = m_eigenSolver.eigenvalues()[i];
447 template <
typename OtherPolynomial>
449 const Index n = m_roots.size();
452 EIGEN_IF_CONSTEXPR (realPolynomial) {
453 for (Index i = 0; i < n; ++i) {
454 if (!(numext::imag(m_roots[i]) > RealScalar(0)))
continue;
456 RealScalar distance = numext::imag(m_roots[i]);
457 for (Index j = 0; j < n; ++j) {
458 if (paired[j] || !(numext::imag(m_roots[j]) < RealScalar(0)))
continue;
459 const RealScalar d = numext::abs(m_roots[j] - numext::conj(m_roots[i]));
466 paired[i] = paired[partner] =
true;
467 const RootType mean = (m_roots[i] + numext::conj(m_roots[partner])) / RealScalar(2);
469 m_roots[partner] = numext::conj(mean);
473 RootType value, derivative;
474 for (Index i = 0; i < n; ++i) {
475 if (numext::imag(m_roots[i]) == RealScalar(0))
continue;
476 const RootType realPart(numext::real(m_roots[i]));
477 if (realPolynomial && !paired[i]) {
478 m_roots[i] = realPart;
482 if (!(numext::abs(numext::imag(m_roots[i])) <=
485 const RealScalar bound = evaluate(poly, realPart, value, derivative,
true);
486 if ((numext::isfinite)(bound) && numext::abs(value) <= bound) m_roots[i] = realPart;
490 using PS_Base::m_roots;
491 EigenSolverType m_eigenSolver;
494template <
typename Scalar_>
495class PolynomialSolver<Scalar_, 1> :
public PolynomialSolverBase<Scalar_, 1> {
497 typedef PolynomialSolverBase<Scalar_, 1> PS_Base;
498 EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES(PS_Base)
502 template <
typename OtherPolynomial>
503 void compute(
const OtherPolynomial& poly) {
504 eigen_assert(poly.size() == 2);
505 eigen_assert(Scalar(0) != poly[1]);
506 m_roots[0] = -poly[0] / poly[1];
510 template <
typename OtherPolynomial>
511 inline PolynomialSolver(
const OtherPolynomial& poly) {
515 inline PolynomialSolver() {}
518 using PS_Base::m_roots;
constexpr void resize(Index rows, Index cols)
const RealScalar & smallestRealRoot(bool &hasArealRoot, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
Definition PolynomialSolver.h:255
const RealScalar & absGreatestRealRoot(bool &hasArealRoot, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
Definition PolynomialSolver.h:195
const RealScalar & absSmallestRealRoot(bool &hasArealRoot, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
Definition PolynomialSolver.h:215
void realRoots(Stl_back_insertion_sequence &bi_seq, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
Definition PolynomialSolver.h:74
const RootType & greatestRoot() const
Definition PolynomialSolver.h:104
const RealScalar & greatestRealRoot(bool &hasArealRoot, const RealScalar &absImaginaryThreshold=NumTraits< Scalar >::dummy_precision()) const
Definition PolynomialSolver.h:235
const RootType & smallestRoot() const
Definition PolynomialSolver.h:112
const RootsType & roots() const
Definition PolynomialSolver.h:60
A polynomial solver.
Definition PolynomialSolver.h:300
void refineRoots(const OtherPolynomial &poly)
Definition PolynomialSolver.h:382
void compute(const OtherPolynomial &poly)
Definition PolynomialSolver.h:316
void cleanUpRoots(const OtherPolynomial &poly)
Definition PolynomialSolver.h:448
Namespace containing all symbols from the Eigen library.