mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
Apply clang-format
This commit is contained in:
@@ -17,267 +17,236 @@
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
template<int Size>
|
||||
struct decrement_if_fixed_size
|
||||
{
|
||||
enum {
|
||||
ret = (Size == Dynamic) ? Dynamic : Size-1 };
|
||||
template <int Size>
|
||||
struct decrement_if_fixed_size {
|
||||
enum { ret = (Size == Dynamic) ? Dynamic : Size - 1 };
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
template< typename Scalar_, int Deg_ >
|
||||
class companion
|
||||
{
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar_,Deg_==Dynamic ? Dynamic : Deg_)
|
||||
template <typename Scalar_, int Deg_>
|
||||
class companion {
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar_, Deg_ == Dynamic ? Dynamic : Deg_)
|
||||
|
||||
enum {
|
||||
Deg = Deg_,
|
||||
Deg_1=decrement_if_fixed_size<Deg>::ret
|
||||
};
|
||||
enum { Deg = Deg_, Deg_1 = decrement_if_fixed_size<Deg>::ret };
|
||||
|
||||
typedef Scalar_ Scalar;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
typedef Matrix<Scalar, Deg, 1> RightColumn;
|
||||
//typedef DiagonalMatrix< Scalar, Deg_1, Deg_1 > BottomLeftDiagonal;
|
||||
typedef Matrix<Scalar, Deg_1, 1> BottomLeftDiagonal;
|
||||
typedef Scalar_ Scalar;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
typedef Matrix<Scalar, Deg, 1> RightColumn;
|
||||
// typedef DiagonalMatrix< Scalar, Deg_1, Deg_1 > BottomLeftDiagonal;
|
||||
typedef Matrix<Scalar, Deg_1, 1> BottomLeftDiagonal;
|
||||
|
||||
typedef Matrix<Scalar, Deg, Deg> DenseCompanionMatrixType;
|
||||
typedef Matrix< Scalar, Deg_, Deg_1 > LeftBlock;
|
||||
typedef Matrix< Scalar, Deg_1, Deg_1 > BottomLeftBlock;
|
||||
typedef Matrix< Scalar, 1, Deg_1 > LeftBlockFirstRow;
|
||||
typedef Matrix<Scalar, Deg, Deg> DenseCompanionMatrixType;
|
||||
typedef Matrix<Scalar, Deg_, Deg_1> LeftBlock;
|
||||
typedef Matrix<Scalar, Deg_1, Deg_1> BottomLeftBlock;
|
||||
typedef Matrix<Scalar, 1, Deg_1> LeftBlockFirstRow;
|
||||
|
||||
typedef DenseIndex Index;
|
||||
typedef DenseIndex Index;
|
||||
|
||||
public:
|
||||
EIGEN_STRONG_INLINE const Scalar_ operator()(Index row, Index col ) const
|
||||
{
|
||||
if( m_bl_diag.rows() > col )
|
||||
{
|
||||
if( 0 < row ){ return m_bl_diag[col]; }
|
||||
else{ return 0; }
|
||||
public:
|
||||
EIGEN_STRONG_INLINE const Scalar_ operator()(Index row, Index col) const {
|
||||
if (m_bl_diag.rows() > col) {
|
||||
if (0 < row) {
|
||||
return m_bl_diag[col];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
else{ return m_monic[row]; }
|
||||
} else {
|
||||
return m_monic[row];
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename VectorType>
|
||||
void setPolynomial( const VectorType& poly )
|
||||
{
|
||||
const Index deg = poly.size()-1;
|
||||
m_monic = -poly.head(deg)/poly[deg];
|
||||
m_bl_diag.setOnes(deg-1);
|
||||
}
|
||||
public:
|
||||
template <typename VectorType>
|
||||
void setPolynomial(const VectorType& poly) {
|
||||
const Index deg = poly.size() - 1;
|
||||
m_monic = -poly.head(deg) / poly[deg];
|
||||
m_bl_diag.setOnes(deg - 1);
|
||||
}
|
||||
|
||||
template<typename VectorType>
|
||||
companion( const VectorType& poly ){
|
||||
setPolynomial( poly ); }
|
||||
template <typename VectorType>
|
||||
companion(const VectorType& poly) {
|
||||
setPolynomial(poly);
|
||||
}
|
||||
|
||||
public:
|
||||
DenseCompanionMatrixType denseMatrix() const
|
||||
{
|
||||
const Index deg = m_monic.size();
|
||||
const Index deg_1 = deg-1;
|
||||
DenseCompanionMatrixType companMat(deg,deg);
|
||||
companMat <<
|
||||
( LeftBlock(deg,deg_1)
|
||||
<< LeftBlockFirstRow::Zero(1,deg_1),
|
||||
BottomLeftBlock::Identity(deg-1,deg-1)*m_bl_diag.asDiagonal() ).finished()
|
||||
, m_monic;
|
||||
return companMat;
|
||||
}
|
||||
public:
|
||||
DenseCompanionMatrixType denseMatrix() const {
|
||||
const Index deg = m_monic.size();
|
||||
const Index deg_1 = deg - 1;
|
||||
DenseCompanionMatrixType companMat(deg, deg);
|
||||
companMat << (LeftBlock(deg, deg_1) << LeftBlockFirstRow::Zero(1, deg_1),
|
||||
BottomLeftBlock::Identity(deg - 1, deg - 1) * m_bl_diag.asDiagonal())
|
||||
.finished(),
|
||||
m_monic;
|
||||
return companMat;
|
||||
}
|
||||
|
||||
protected:
|
||||
/** Helper function for the balancing algorithm.
|
||||
* \returns true if the row and the column, having colNorm and rowNorm
|
||||
* as norms, are balanced, false otherwise.
|
||||
* colB and rowB are respectively the multipliers for
|
||||
* the column and the row in order to balance them.
|
||||
* */
|
||||
bool balanced(RealScalar colNorm, RealScalar rowNorm, bool& isBalanced, RealScalar& colB, RealScalar& rowB);
|
||||
|
||||
/** Helper function for the balancing algorithm.
|
||||
* \returns true if the row and the column, having colNorm and rowNorm
|
||||
* as norms, are balanced, false otherwise.
|
||||
* colB and rowB are respectively the multipliers for
|
||||
* the column and the row in order to balance them.
|
||||
* */
|
||||
bool balancedR(RealScalar colNorm, RealScalar rowNorm, bool& isBalanced, RealScalar& colB, RealScalar& rowB);
|
||||
|
||||
protected:
|
||||
/** Helper function for the balancing algorithm.
|
||||
* \returns true if the row and the column, having colNorm and rowNorm
|
||||
* as norms, are balanced, false otherwise.
|
||||
* colB and rowB are respectively the multipliers for
|
||||
* the column and the row in order to balance them.
|
||||
* */
|
||||
bool balanced( RealScalar colNorm, RealScalar rowNorm,
|
||||
bool& isBalanced, RealScalar& colB, RealScalar& rowB );
|
||||
public:
|
||||
/**
|
||||
* Balancing algorithm from B. N. PARLETT and C. REINSCH (1969)
|
||||
* "Balancing a matrix for calculation of eigenvalues and eigenvectors"
|
||||
* adapted to the case of companion matrices.
|
||||
* A matrix with non zero row and non zero column is balanced
|
||||
* for a certain norm if the i-th row and the i-th column
|
||||
* have same norm for all i.
|
||||
*/
|
||||
void balance();
|
||||
|
||||
/** Helper function for the balancing algorithm.
|
||||
* \returns true if the row and the column, having colNorm and rowNorm
|
||||
* as norms, are balanced, false otherwise.
|
||||
* colB and rowB are respectively the multipliers for
|
||||
* the column and the row in order to balance them.
|
||||
* */
|
||||
bool balancedR( RealScalar colNorm, RealScalar rowNorm,
|
||||
bool& isBalanced, RealScalar& colB, RealScalar& rowB );
|
||||
|
||||
public:
|
||||
/**
|
||||
* Balancing algorithm from B. N. PARLETT and C. REINSCH (1969)
|
||||
* "Balancing a matrix for calculation of eigenvalues and eigenvectors"
|
||||
* adapted to the case of companion matrices.
|
||||
* A matrix with non zero row and non zero column is balanced
|
||||
* for a certain norm if the i-th row and the i-th column
|
||||
* have same norm for all i.
|
||||
*/
|
||||
void balance();
|
||||
|
||||
protected:
|
||||
RightColumn m_monic;
|
||||
BottomLeftDiagonal m_bl_diag;
|
||||
protected:
|
||||
RightColumn m_monic;
|
||||
BottomLeftDiagonal m_bl_diag;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template< typename Scalar_, int Deg_ >
|
||||
inline
|
||||
bool companion<Scalar_,Deg_>::balanced( RealScalar colNorm, RealScalar rowNorm,
|
||||
bool& isBalanced, RealScalar& colB, RealScalar& rowB )
|
||||
{
|
||||
if( RealScalar(0) == colNorm || RealScalar(0) == rowNorm
|
||||
|| !(numext::isfinite)(colNorm) || !(numext::isfinite)(rowNorm)){
|
||||
template <typename Scalar_, int Deg_>
|
||||
inline bool companion<Scalar_, Deg_>::balanced(RealScalar colNorm, RealScalar rowNorm, bool& isBalanced,
|
||||
RealScalar& colB, RealScalar& rowB) {
|
||||
if (RealScalar(0) == colNorm || RealScalar(0) == rowNorm || !(numext::isfinite)(colNorm) ||
|
||||
!(numext::isfinite)(rowNorm)) {
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//To find the balancing coefficients, if the radix is 2,
|
||||
//one finds \f$ \sigma \f$ such that
|
||||
// \f$ 2^{2\sigma-1} < rowNorm / colNorm \le 2^{2\sigma+1} \f$
|
||||
// then the balancing coefficient for the row is \f$ 1/2^{\sigma} \f$
|
||||
// and the balancing coefficient for the column is \f$ 2^{\sigma} \f$
|
||||
} else {
|
||||
// To find the balancing coefficients, if the radix is 2,
|
||||
// one finds \f$ \sigma \f$ such that
|
||||
// \f$ 2^{2\sigma-1} < rowNorm / colNorm \le 2^{2\sigma+1} \f$
|
||||
// then the balancing coefficient for the row is \f$ 1/2^{\sigma} \f$
|
||||
// and the balancing coefficient for the column is \f$ 2^{\sigma} \f$
|
||||
const RealScalar radix = RealScalar(2);
|
||||
const RealScalar radix2 = RealScalar(4);
|
||||
|
||||
|
||||
rowB = rowNorm / radix;
|
||||
colB = RealScalar(1);
|
||||
const RealScalar s = colNorm + rowNorm;
|
||||
|
||||
// Find sigma s.t. rowNorm / 2 <= 2^(2*sigma) * colNorm
|
||||
RealScalar scout = colNorm;
|
||||
while (scout < rowB)
|
||||
{
|
||||
while (scout < rowB) {
|
||||
colB *= radix;
|
||||
scout *= radix2;
|
||||
}
|
||||
|
||||
|
||||
// We now have an upper-bound for sigma, try to lower it.
|
||||
// Find sigma s.t. 2^(2*sigma) * colNorm / 2 < rowNorm
|
||||
scout = colNorm * (colB / radix) * colB; // Avoid overflow.
|
||||
while (scout >= rowNorm)
|
||||
{
|
||||
while (scout >= rowNorm) {
|
||||
colB /= radix;
|
||||
scout /= radix2;
|
||||
}
|
||||
|
||||
// This line is used to avoid insubstantial balancing.
|
||||
if ((rowNorm + radix * scout) < RealScalar(0.95) * s * colB)
|
||||
{
|
||||
if ((rowNorm + radix * scout) < RealScalar(0.95) * s * colB) {
|
||||
isBalanced = false;
|
||||
rowB = RealScalar(1) / colB;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template< typename Scalar_, int Deg_ >
|
||||
inline
|
||||
bool companion<Scalar_,Deg_>::balancedR( RealScalar colNorm, RealScalar rowNorm,
|
||||
bool& isBalanced, RealScalar& colB, RealScalar& rowB )
|
||||
{
|
||||
if( RealScalar(0) == colNorm || RealScalar(0) == rowNorm ){ return true; }
|
||||
else
|
||||
{
|
||||
template <typename Scalar_, int Deg_>
|
||||
inline bool companion<Scalar_, Deg_>::balancedR(RealScalar colNorm, RealScalar rowNorm, bool& isBalanced,
|
||||
RealScalar& colB, RealScalar& rowB) {
|
||||
if (RealScalar(0) == colNorm || RealScalar(0) == rowNorm) {
|
||||
return true;
|
||||
} else {
|
||||
/**
|
||||
* Set the norm of the column and the row to the geometric mean
|
||||
* of the row and column norm
|
||||
*/
|
||||
const RealScalar q = colNorm/rowNorm;
|
||||
if( !isApprox( q, Scalar_(1) ) )
|
||||
{
|
||||
rowB = sqrt( colNorm/rowNorm );
|
||||
colB = RealScalar(1)/rowB;
|
||||
const RealScalar q = colNorm / rowNorm;
|
||||
if (!isApprox(q, Scalar_(1))) {
|
||||
rowB = sqrt(colNorm / rowNorm);
|
||||
colB = RealScalar(1) / rowB;
|
||||
|
||||
isBalanced = false;
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
return true; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template< typename Scalar_, int Deg_ >
|
||||
void companion<Scalar_,Deg_>::balance()
|
||||
{
|
||||
template <typename Scalar_, int Deg_>
|
||||
void companion<Scalar_, Deg_>::balance() {
|
||||
using std::abs;
|
||||
EIGEN_STATIC_ASSERT( Deg == Dynamic || 1 < Deg, YOU_MADE_A_PROGRAMMING_MISTAKE );
|
||||
const Index deg = m_monic.size();
|
||||
const Index deg_1 = deg-1;
|
||||
EIGEN_STATIC_ASSERT(Deg == Dynamic || 1 < Deg, YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
const Index deg = m_monic.size();
|
||||
const Index deg_1 = deg - 1;
|
||||
|
||||
bool hasConverged=false;
|
||||
while( !hasConverged )
|
||||
{
|
||||
bool hasConverged = false;
|
||||
while (!hasConverged) {
|
||||
hasConverged = true;
|
||||
RealScalar colNorm,rowNorm;
|
||||
RealScalar colB,rowB;
|
||||
RealScalar colNorm, rowNorm;
|
||||
RealScalar colB, rowB;
|
||||
|
||||
//First row, first column excluding the diagonal
|
||||
// First row, first column excluding the diagonal
|
||||
//==============================================
|
||||
colNorm = abs(m_bl_diag[0]);
|
||||
rowNorm = abs(m_monic[0]);
|
||||
|
||||
//Compute balancing of the row and the column
|
||||
if( !balanced( colNorm, rowNorm, hasConverged, colB, rowB ) )
|
||||
{
|
||||
// Compute balancing of the row and the column
|
||||
if (!balanced(colNorm, rowNorm, hasConverged, colB, rowB)) {
|
||||
m_bl_diag[0] *= colB;
|
||||
m_monic[0] *= rowB;
|
||||
}
|
||||
|
||||
//Middle rows and columns excluding the diagonal
|
||||
// Middle rows and columns excluding the diagonal
|
||||
//==============================================
|
||||
for( Index i=1; i<deg_1; ++i )
|
||||
{
|
||||
for (Index i = 1; i < deg_1; ++i) {
|
||||
// column norm, excluding the diagonal
|
||||
colNorm = abs(m_bl_diag[i]);
|
||||
|
||||
// row norm, excluding the diagonal
|
||||
rowNorm = abs(m_bl_diag[i-1]) + abs(m_monic[i]);
|
||||
rowNorm = abs(m_bl_diag[i - 1]) + abs(m_monic[i]);
|
||||
|
||||
//Compute balancing of the row and the column
|
||||
if( !balanced( colNorm, rowNorm, hasConverged, colB, rowB ) )
|
||||
{
|
||||
m_bl_diag[i] *= colB;
|
||||
m_bl_diag[i-1] *= rowB;
|
||||
m_monic[i] *= rowB;
|
||||
// Compute balancing of the row and the column
|
||||
if (!balanced(colNorm, rowNorm, hasConverged, colB, rowB)) {
|
||||
m_bl_diag[i] *= colB;
|
||||
m_bl_diag[i - 1] *= rowB;
|
||||
m_monic[i] *= rowB;
|
||||
}
|
||||
}
|
||||
|
||||
//Last row, last column excluding the diagonal
|
||||
// Last row, last column excluding the diagonal
|
||||
//============================================
|
||||
const Index ebl = m_bl_diag.size()-1;
|
||||
VectorBlock<RightColumn,Deg_1> headMonic( m_monic, 0, deg_1 );
|
||||
const Index ebl = m_bl_diag.size() - 1;
|
||||
VectorBlock<RightColumn, Deg_1> headMonic(m_monic, 0, deg_1);
|
||||
colNorm = headMonic.array().abs().sum();
|
||||
rowNorm = abs( m_bl_diag[ebl] );
|
||||
rowNorm = abs(m_bl_diag[ebl]);
|
||||
|
||||
//Compute balancing of the row and the column
|
||||
if( !balanced( colNorm, rowNorm, hasConverged, colB, rowB ) )
|
||||
{
|
||||
headMonic *= colB;
|
||||
// Compute balancing of the row and the column
|
||||
if (!balanced(colNorm, rowNorm, hasConverged, colB, rowB)) {
|
||||
headMonic *= colB;
|
||||
m_bl_diag[ebl] *= rowB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_COMPANION_H
|
||||
#endif // EIGEN_COMPANION_H
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
namespace Eigen {
|
||||
|
||||
/** \ingroup Polynomials_Module
|
||||
* \class PolynomialSolverBase.
|
||||
@@ -28,404 +28,359 @@ namespace Eigen {
|
||||
* It stores the set of roots as a vector of complexes.
|
||||
*
|
||||
*/
|
||||
template< typename Scalar_, int Deg_ >
|
||||
class PolynomialSolverBase
|
||||
{
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar_,Deg_==Dynamic ? Dynamic : Deg_)
|
||||
template <typename Scalar_, int Deg_>
|
||||
class PolynomialSolverBase {
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar_, Deg_ == Dynamic ? Dynamic : Deg_)
|
||||
|
||||
typedef Scalar_ Scalar;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
typedef std::complex<RealScalar> RootType;
|
||||
typedef Matrix<RootType,Deg_,1> RootsType;
|
||||
typedef Scalar_ Scalar;
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
typedef std::complex<RealScalar> RootType;
|
||||
typedef Matrix<RootType, Deg_, 1> RootsType;
|
||||
|
||||
typedef DenseIndex Index;
|
||||
typedef DenseIndex Index;
|
||||
|
||||
protected:
|
||||
template< typename OtherPolynomial >
|
||||
inline void setPolynomial( const OtherPolynomial& poly ){
|
||||
m_roots.resize(poly.size()-1); }
|
||||
protected:
|
||||
template <typename OtherPolynomial>
|
||||
inline void setPolynomial(const OtherPolynomial& poly) {
|
||||
m_roots.resize(poly.size() - 1);
|
||||
}
|
||||
|
||||
public:
|
||||
template< typename OtherPolynomial >
|
||||
inline PolynomialSolverBase( const OtherPolynomial& poly ){
|
||||
setPolynomial( poly() ); }
|
||||
public:
|
||||
template <typename OtherPolynomial>
|
||||
inline PolynomialSolverBase(const OtherPolynomial& poly) {
|
||||
setPolynomial(poly());
|
||||
}
|
||||
|
||||
inline PolynomialSolverBase(){}
|
||||
inline PolynomialSolverBase() {}
|
||||
|
||||
public:
|
||||
/** \returns the complex roots of the polynomial */
|
||||
inline const RootsType& roots() const { return m_roots; }
|
||||
public:
|
||||
/** \returns the complex roots of the polynomial */
|
||||
inline const RootsType& roots() const { return m_roots; }
|
||||
|
||||
public:
|
||||
/** Clear and fills the back insertion sequence with the real roots of the polynomial
|
||||
* i.e. the real part of the complex roots that have an imaginary part which
|
||||
* absolute value is smaller than absImaginaryThreshold.
|
||||
* absImaginaryThreshold takes the dummy_precision associated
|
||||
* with the Scalar_ template parameter of the PolynomialSolver class as the default value.
|
||||
*
|
||||
* \param[out] bi_seq : the back insertion sequence (stl concept)
|
||||
* \param[in] absImaginaryThreshold : the maximum bound of the imaginary part of a complex
|
||||
* number that is considered as real.
|
||||
* */
|
||||
template<typename Stl_back_insertion_sequence>
|
||||
inline void realRoots( Stl_back_insertion_sequence& bi_seq,
|
||||
const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
|
||||
{
|
||||
using std::abs;
|
||||
bi_seq.clear();
|
||||
for(Index i=0; i<m_roots.size(); ++i )
|
||||
{
|
||||
if( abs( m_roots[i].imag() ) < absImaginaryThreshold ){
|
||||
bi_seq.push_back( m_roots[i].real() ); }
|
||||
public:
|
||||
/** Clear and fills the back insertion sequence with the real roots of the polynomial
|
||||
* i.e. the real part of the complex roots that have an imaginary part which
|
||||
* absolute value is smaller than absImaginaryThreshold.
|
||||
* absImaginaryThreshold takes the dummy_precision associated
|
||||
* with the Scalar_ template parameter of the PolynomialSolver class as the default value.
|
||||
*
|
||||
* \param[out] bi_seq : the back insertion sequence (stl concept)
|
||||
* \param[in] absImaginaryThreshold : the maximum bound of the imaginary part of a complex
|
||||
* number that is considered as real.
|
||||
* */
|
||||
template <typename Stl_back_insertion_sequence>
|
||||
inline void realRoots(Stl_back_insertion_sequence& bi_seq,
|
||||
const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision()) const {
|
||||
using std::abs;
|
||||
bi_seq.clear();
|
||||
for (Index i = 0; i < m_roots.size(); ++i) {
|
||||
if (abs(m_roots[i].imag()) < absImaginaryThreshold) {
|
||||
bi_seq.push_back(m_roots[i].real());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
template<typename squaredNormBinaryPredicate>
|
||||
inline const RootType& selectComplexRoot_withRespectToNorm( squaredNormBinaryPredicate& pred ) const
|
||||
{
|
||||
Index res=0;
|
||||
RealScalar norm2 = numext::abs2( m_roots[0] );
|
||||
for( Index i=1; i<m_roots.size(); ++i )
|
||||
{
|
||||
const RealScalar currNorm2 = numext::abs2( m_roots[i] );
|
||||
if( pred( currNorm2, norm2 ) ){
|
||||
res=i; norm2=currNorm2; }
|
||||
protected:
|
||||
template <typename squaredNormBinaryPredicate>
|
||||
inline const RootType& selectComplexRoot_withRespectToNorm(squaredNormBinaryPredicate& pred) const {
|
||||
Index res = 0;
|
||||
RealScalar norm2 = numext::abs2(m_roots[0]);
|
||||
for (Index i = 1; i < m_roots.size(); ++i) {
|
||||
const RealScalar currNorm2 = numext::abs2(m_roots[i]);
|
||||
if (pred(currNorm2, norm2)) {
|
||||
res = i;
|
||||
norm2 = currNorm2;
|
||||
}
|
||||
return m_roots[res];
|
||||
}
|
||||
return m_roots[res];
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* \returns the complex root with greatest norm.
|
||||
*/
|
||||
inline const RootType& greatestRoot() const
|
||||
{
|
||||
std::greater<RealScalar> greater;
|
||||
return selectComplexRoot_withRespectToNorm( greater );
|
||||
}
|
||||
public:
|
||||
/**
|
||||
* \returns the complex root with greatest norm.
|
||||
*/
|
||||
inline const RootType& greatestRoot() const {
|
||||
std::greater<RealScalar> greater;
|
||||
return selectComplexRoot_withRespectToNorm(greater);
|
||||
}
|
||||
|
||||
/**
|
||||
* \returns the complex root with smallest norm.
|
||||
*/
|
||||
inline const RootType& smallestRoot() const
|
||||
{
|
||||
std::less<RealScalar> less;
|
||||
return selectComplexRoot_withRespectToNorm( less );
|
||||
}
|
||||
/**
|
||||
* \returns the complex root with smallest norm.
|
||||
*/
|
||||
inline const RootType& smallestRoot() const {
|
||||
std::less<RealScalar> less;
|
||||
return selectComplexRoot_withRespectToNorm(less);
|
||||
}
|
||||
|
||||
protected:
|
||||
template<typename squaredRealPartBinaryPredicate>
|
||||
inline const RealScalar& selectRealRoot_withRespectToAbsRealPart(
|
||||
squaredRealPartBinaryPredicate& pred,
|
||||
bool& hasArealRoot,
|
||||
const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
|
||||
{
|
||||
using std::abs;
|
||||
hasArealRoot = false;
|
||||
Index res=0;
|
||||
RealScalar abs2(0);
|
||||
protected:
|
||||
template <typename squaredRealPartBinaryPredicate>
|
||||
inline const RealScalar& selectRealRoot_withRespectToAbsRealPart(
|
||||
squaredRealPartBinaryPredicate& pred, bool& hasArealRoot,
|
||||
const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision()) const {
|
||||
using std::abs;
|
||||
hasArealRoot = false;
|
||||
Index res = 0;
|
||||
RealScalar abs2(0);
|
||||
|
||||
for( Index i=0; i<m_roots.size(); ++i )
|
||||
{
|
||||
if( abs( m_roots[i].imag() ) <= absImaginaryThreshold )
|
||||
{
|
||||
if( !hasArealRoot )
|
||||
{
|
||||
hasArealRoot = true;
|
||||
for (Index i = 0; i < m_roots.size(); ++i) {
|
||||
if (abs(m_roots[i].imag()) <= absImaginaryThreshold) {
|
||||
if (!hasArealRoot) {
|
||||
hasArealRoot = true;
|
||||
res = i;
|
||||
abs2 = m_roots[i].real() * m_roots[i].real();
|
||||
} else {
|
||||
const RealScalar currAbs2 = m_roots[i].real() * m_roots[i].real();
|
||||
if (pred(currAbs2, abs2)) {
|
||||
abs2 = currAbs2;
|
||||
res = i;
|
||||
abs2 = m_roots[i].real() * m_roots[i].real();
|
||||
}
|
||||
else
|
||||
{
|
||||
const RealScalar currAbs2 = m_roots[i].real() * m_roots[i].real();
|
||||
if( pred( currAbs2, abs2 ) )
|
||||
{
|
||||
abs2 = currAbs2;
|
||||
res = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(!hasArealRoot)
|
||||
{
|
||||
if( abs( m_roots[i].imag() ) < abs( m_roots[res].imag() ) ){
|
||||
res = i;}
|
||||
} else if (!hasArealRoot) {
|
||||
if (abs(m_roots[i].imag()) < abs(m_roots[res].imag())) {
|
||||
res = i;
|
||||
}
|
||||
}
|
||||
return numext::real_ref(m_roots[res]);
|
||||
}
|
||||
return numext::real_ref(m_roots[res]);
|
||||
}
|
||||
|
||||
template <typename RealPartBinaryPredicate>
|
||||
inline const RealScalar& selectRealRoot_withRespectToRealPart(
|
||||
RealPartBinaryPredicate& pred, bool& hasArealRoot,
|
||||
const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision()) const {
|
||||
using std::abs;
|
||||
hasArealRoot = false;
|
||||
Index res = 0;
|
||||
RealScalar val(0);
|
||||
|
||||
template<typename RealPartBinaryPredicate>
|
||||
inline const RealScalar& selectRealRoot_withRespectToRealPart(
|
||||
RealPartBinaryPredicate& pred,
|
||||
bool& hasArealRoot,
|
||||
const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
|
||||
{
|
||||
using std::abs;
|
||||
hasArealRoot = false;
|
||||
Index res=0;
|
||||
RealScalar val(0);
|
||||
|
||||
for( Index i=0; i<m_roots.size(); ++i )
|
||||
{
|
||||
if( abs( m_roots[i].imag() ) <= absImaginaryThreshold )
|
||||
{
|
||||
if( !hasArealRoot )
|
||||
{
|
||||
hasArealRoot = true;
|
||||
for (Index i = 0; i < m_roots.size(); ++i) {
|
||||
if (abs(m_roots[i].imag()) <= absImaginaryThreshold) {
|
||||
if (!hasArealRoot) {
|
||||
hasArealRoot = true;
|
||||
res = i;
|
||||
val = m_roots[i].real();
|
||||
} else {
|
||||
const RealScalar curr = m_roots[i].real();
|
||||
if (pred(curr, val)) {
|
||||
val = curr;
|
||||
res = i;
|
||||
val = m_roots[i].real();
|
||||
}
|
||||
else
|
||||
{
|
||||
const RealScalar curr = m_roots[i].real();
|
||||
if( pred( curr, val ) )
|
||||
{
|
||||
val = curr;
|
||||
res = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( abs( m_roots[i].imag() ) < abs( m_roots[res].imag() ) ){
|
||||
res = i; }
|
||||
} else {
|
||||
if (abs(m_roots[i].imag()) < abs(m_roots[res].imag())) {
|
||||
res = i;
|
||||
}
|
||||
}
|
||||
return numext::real_ref(m_roots[res]);
|
||||
}
|
||||
return numext::real_ref(m_roots[res]);
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* \returns a real root with greatest absolute magnitude.
|
||||
* A real root is defined as the real part of a complex root with absolute imaginary
|
||||
* part smallest than absImaginaryThreshold.
|
||||
* absImaginaryThreshold takes the dummy_precision associated
|
||||
* with the Scalar_ template parameter of the PolynomialSolver class as the default value.
|
||||
* If no real root is found the boolean hasArealRoot is set to false and the real part of
|
||||
* the root with smallest absolute imaginary part is returned instead.
|
||||
*
|
||||
* \param[out] hasArealRoot : boolean true if a real root is found according to the
|
||||
* absImaginaryThreshold criterion, false otherwise.
|
||||
* \param[in] absImaginaryThreshold : threshold on the absolute imaginary part to decide
|
||||
* whether or not a root is real.
|
||||
*/
|
||||
inline const RealScalar& absGreatestRealRoot(
|
||||
bool& hasArealRoot,
|
||||
const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
|
||||
{
|
||||
std::greater<RealScalar> greater;
|
||||
return selectRealRoot_withRespectToAbsRealPart( greater, hasArealRoot, absImaginaryThreshold );
|
||||
}
|
||||
public:
|
||||
/**
|
||||
* \returns a real root with greatest absolute magnitude.
|
||||
* A real root is defined as the real part of a complex root with absolute imaginary
|
||||
* part smallest than absImaginaryThreshold.
|
||||
* absImaginaryThreshold takes the dummy_precision associated
|
||||
* with the Scalar_ template parameter of the PolynomialSolver class as the default value.
|
||||
* If no real root is found the boolean hasArealRoot is set to false and the real part of
|
||||
* the root with smallest absolute imaginary part is returned instead.
|
||||
*
|
||||
* \param[out] hasArealRoot : boolean true if a real root is found according to the
|
||||
* absImaginaryThreshold criterion, false otherwise.
|
||||
* \param[in] absImaginaryThreshold : threshold on the absolute imaginary part to decide
|
||||
* whether or not a root is real.
|
||||
*/
|
||||
inline const RealScalar& absGreatestRealRoot(
|
||||
bool& hasArealRoot, const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision()) const {
|
||||
std::greater<RealScalar> greater;
|
||||
return selectRealRoot_withRespectToAbsRealPart(greater, hasArealRoot, absImaginaryThreshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* \returns a real root with smallest absolute magnitude.
|
||||
* A real root is defined as the real part of a complex root with absolute imaginary
|
||||
* part smallest than absImaginaryThreshold.
|
||||
* absImaginaryThreshold takes the dummy_precision associated
|
||||
* with the Scalar_ template parameter of the PolynomialSolver class as the default value.
|
||||
* If no real root is found the boolean hasArealRoot is set to false and the real part of
|
||||
* the root with smallest absolute imaginary part is returned instead.
|
||||
*
|
||||
* \param[out] hasArealRoot : boolean true if a real root is found according to the
|
||||
* absImaginaryThreshold criterion, false otherwise.
|
||||
* \param[in] absImaginaryThreshold : threshold on the absolute imaginary part to decide
|
||||
* whether or not a root is real.
|
||||
*/
|
||||
inline const RealScalar& absSmallestRealRoot(
|
||||
bool& hasArealRoot, const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision()) const {
|
||||
std::less<RealScalar> less;
|
||||
return selectRealRoot_withRespectToAbsRealPart(less, hasArealRoot, absImaginaryThreshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* \returns a real root with smallest absolute magnitude.
|
||||
* A real root is defined as the real part of a complex root with absolute imaginary
|
||||
* part smallest than absImaginaryThreshold.
|
||||
* absImaginaryThreshold takes the dummy_precision associated
|
||||
* with the Scalar_ template parameter of the PolynomialSolver class as the default value.
|
||||
* If no real root is found the boolean hasArealRoot is set to false and the real part of
|
||||
* the root with smallest absolute imaginary part is returned instead.
|
||||
*
|
||||
* \param[out] hasArealRoot : boolean true if a real root is found according to the
|
||||
* absImaginaryThreshold criterion, false otherwise.
|
||||
* \param[in] absImaginaryThreshold : threshold on the absolute imaginary part to decide
|
||||
* whether or not a root is real.
|
||||
*/
|
||||
inline const RealScalar& absSmallestRealRoot(
|
||||
bool& hasArealRoot,
|
||||
const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
|
||||
{
|
||||
std::less<RealScalar> less;
|
||||
return selectRealRoot_withRespectToAbsRealPart( less, hasArealRoot, absImaginaryThreshold );
|
||||
}
|
||||
/**
|
||||
* \returns the real root with greatest value.
|
||||
* A real root is defined as the real part of a complex root with absolute imaginary
|
||||
* part smallest than absImaginaryThreshold.
|
||||
* absImaginaryThreshold takes the dummy_precision associated
|
||||
* with the Scalar_ template parameter of the PolynomialSolver class as the default value.
|
||||
* If no real root is found the boolean hasArealRoot is set to false and the real part of
|
||||
* the root with smallest absolute imaginary part is returned instead.
|
||||
*
|
||||
* \param[out] hasArealRoot : boolean true if a real root is found according to the
|
||||
* absImaginaryThreshold criterion, false otherwise.
|
||||
* \param[in] absImaginaryThreshold : threshold on the absolute imaginary part to decide
|
||||
* whether or not a root is real.
|
||||
*/
|
||||
inline const RealScalar& greatestRealRoot(
|
||||
bool& hasArealRoot, const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision()) const {
|
||||
std::greater<RealScalar> greater;
|
||||
return selectRealRoot_withRespectToRealPart(greater, hasArealRoot, absImaginaryThreshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* \returns the real root with smallest value.
|
||||
* A real root is defined as the real part of a complex root with absolute imaginary
|
||||
* part smallest than absImaginaryThreshold.
|
||||
* absImaginaryThreshold takes the dummy_precision associated
|
||||
* with the Scalar_ template parameter of the PolynomialSolver class as the default value.
|
||||
* If no real root is found the boolean hasArealRoot is set to false and the real part of
|
||||
* the root with smallest absolute imaginary part is returned instead.
|
||||
*
|
||||
* \param[out] hasArealRoot : boolean true if a real root is found according to the
|
||||
* absImaginaryThreshold criterion, false otherwise.
|
||||
* \param[in] absImaginaryThreshold : threshold on the absolute imaginary part to decide
|
||||
* whether or not a root is real.
|
||||
*/
|
||||
inline const RealScalar& smallestRealRoot(
|
||||
bool& hasArealRoot, const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision()) const {
|
||||
std::less<RealScalar> less;
|
||||
return selectRealRoot_withRespectToRealPart(less, hasArealRoot, absImaginaryThreshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* \returns the real root with greatest value.
|
||||
* A real root is defined as the real part of a complex root with absolute imaginary
|
||||
* part smallest than absImaginaryThreshold.
|
||||
* absImaginaryThreshold takes the dummy_precision associated
|
||||
* with the Scalar_ template parameter of the PolynomialSolver class as the default value.
|
||||
* If no real root is found the boolean hasArealRoot is set to false and the real part of
|
||||
* the root with smallest absolute imaginary part is returned instead.
|
||||
*
|
||||
* \param[out] hasArealRoot : boolean true if a real root is found according to the
|
||||
* absImaginaryThreshold criterion, false otherwise.
|
||||
* \param[in] absImaginaryThreshold : threshold on the absolute imaginary part to decide
|
||||
* whether or not a root is real.
|
||||
*/
|
||||
inline const RealScalar& greatestRealRoot(
|
||||
bool& hasArealRoot,
|
||||
const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
|
||||
{
|
||||
std::greater<RealScalar> greater;
|
||||
return selectRealRoot_withRespectToRealPart( greater, hasArealRoot, absImaginaryThreshold );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \returns the real root with smallest value.
|
||||
* A real root is defined as the real part of a complex root with absolute imaginary
|
||||
* part smallest than absImaginaryThreshold.
|
||||
* absImaginaryThreshold takes the dummy_precision associated
|
||||
* with the Scalar_ template parameter of the PolynomialSolver class as the default value.
|
||||
* If no real root is found the boolean hasArealRoot is set to false and the real part of
|
||||
* the root with smallest absolute imaginary part is returned instead.
|
||||
*
|
||||
* \param[out] hasArealRoot : boolean true if a real root is found according to the
|
||||
* absImaginaryThreshold criterion, false otherwise.
|
||||
* \param[in] absImaginaryThreshold : threshold on the absolute imaginary part to decide
|
||||
* whether or not a root is real.
|
||||
*/
|
||||
inline const RealScalar& smallestRealRoot(
|
||||
bool& hasArealRoot,
|
||||
const RealScalar& absImaginaryThreshold = NumTraits<Scalar>::dummy_precision() ) const
|
||||
{
|
||||
std::less<RealScalar> less;
|
||||
return selectRealRoot_withRespectToRealPart( less, hasArealRoot, absImaginaryThreshold );
|
||||
}
|
||||
|
||||
protected:
|
||||
RootsType m_roots;
|
||||
protected:
|
||||
RootsType m_roots;
|
||||
};
|
||||
|
||||
#define EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES( BASE ) \
|
||||
typedef typename BASE::Scalar Scalar; \
|
||||
typedef typename BASE::RealScalar RealScalar; \
|
||||
typedef typename BASE::RootType RootType; \
|
||||
typedef typename BASE::RootsType RootsType;
|
||||
|
||||
|
||||
#define EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES(BASE) \
|
||||
typedef typename BASE::Scalar Scalar; \
|
||||
typedef typename BASE::RealScalar RealScalar; \
|
||||
typedef typename BASE::RootType RootType; \
|
||||
typedef typename BASE::RootsType RootsType;
|
||||
|
||||
/** \ingroup Polynomials_Module
|
||||
*
|
||||
* \class PolynomialSolver
|
||||
*
|
||||
* \brief A polynomial solver
|
||||
*
|
||||
* Computes the complex roots of a real polynomial.
|
||||
*
|
||||
* \param Scalar_ the scalar type, i.e., the type of the polynomial coefficients
|
||||
* \param Deg_ the degree of the polynomial, can be a compile time value or Dynamic.
|
||||
* Notice that the number of polynomial coefficients is Deg_+1.
|
||||
*
|
||||
* This class implements a polynomial solver and provides convenient methods such as
|
||||
* - real roots,
|
||||
* - greatest, smallest complex roots,
|
||||
* - real roots with greatest, smallest absolute real value.
|
||||
* - greatest, smallest real roots.
|
||||
*
|
||||
* WARNING: this polynomial solver is experimental, part of the unsupported Eigen modules.
|
||||
*
|
||||
*
|
||||
* Currently a QR algorithm is used to compute the eigenvalues of the companion matrix of
|
||||
* the polynomial to compute its roots.
|
||||
* This supposes that the complex moduli of the roots are all distinct: e.g. there should
|
||||
* be no multiple roots or conjugate roots for instance.
|
||||
* With 32bit (float) floating types this problem shows up frequently.
|
||||
* However, almost always, correct accuracy is reached even in these cases for 64bit
|
||||
* (double) floating types and small polynomial degree (<20).
|
||||
*/
|
||||
template<typename Scalar_, int Deg_>
|
||||
class PolynomialSolver : public PolynomialSolverBase<Scalar_,Deg_>
|
||||
{
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar_,Deg_==Dynamic ? Dynamic : Deg_)
|
||||
*
|
||||
* \class PolynomialSolver
|
||||
*
|
||||
* \brief A polynomial solver
|
||||
*
|
||||
* Computes the complex roots of a real polynomial.
|
||||
*
|
||||
* \param Scalar_ the scalar type, i.e., the type of the polynomial coefficients
|
||||
* \param Deg_ the degree of the polynomial, can be a compile time value or Dynamic.
|
||||
* Notice that the number of polynomial coefficients is Deg_+1.
|
||||
*
|
||||
* This class implements a polynomial solver and provides convenient methods such as
|
||||
* - real roots,
|
||||
* - greatest, smallest complex roots,
|
||||
* - real roots with greatest, smallest absolute real value.
|
||||
* - greatest, smallest real roots.
|
||||
*
|
||||
* WARNING: this polynomial solver is experimental, part of the unsupported Eigen modules.
|
||||
*
|
||||
*
|
||||
* Currently a QR algorithm is used to compute the eigenvalues of the companion matrix of
|
||||
* the polynomial to compute its roots.
|
||||
* This supposes that the complex moduli of the roots are all distinct: e.g. there should
|
||||
* be no multiple roots or conjugate roots for instance.
|
||||
* With 32bit (float) floating types this problem shows up frequently.
|
||||
* However, almost always, correct accuracy is reached even in these cases for 64bit
|
||||
* (double) floating types and small polynomial degree (<20).
|
||||
*/
|
||||
template <typename Scalar_, int Deg_>
|
||||
class PolynomialSolver : public PolynomialSolverBase<Scalar_, Deg_> {
|
||||
public:
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE(Scalar_, Deg_ == Dynamic ? Dynamic : Deg_)
|
||||
|
||||
typedef PolynomialSolverBase<Scalar_,Deg_> PS_Base;
|
||||
EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES( PS_Base )
|
||||
typedef PolynomialSolverBase<Scalar_, Deg_> PS_Base;
|
||||
EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES(PS_Base)
|
||||
|
||||
typedef Matrix<Scalar,Deg_,Deg_> CompanionMatrixType;
|
||||
typedef std::conditional_t<NumTraits<Scalar>::IsComplex,
|
||||
ComplexEigenSolver<CompanionMatrixType>,
|
||||
EigenSolver<CompanionMatrixType> > EigenSolverType;
|
||||
typedef std::conditional_t<NumTraits<Scalar>::IsComplex, Scalar, std::complex<Scalar> > ComplexScalar;
|
||||
typedef Matrix<Scalar, Deg_, Deg_> CompanionMatrixType;
|
||||
typedef std::conditional_t<NumTraits<Scalar>::IsComplex, ComplexEigenSolver<CompanionMatrixType>,
|
||||
EigenSolver<CompanionMatrixType> >
|
||||
EigenSolverType;
|
||||
typedef std::conditional_t<NumTraits<Scalar>::IsComplex, Scalar, std::complex<Scalar> > ComplexScalar;
|
||||
|
||||
public:
|
||||
/** Computes the complex roots of a new polynomial. */
|
||||
template< typename OtherPolynomial >
|
||||
void compute( const OtherPolynomial& poly )
|
||||
{
|
||||
eigen_assert( Scalar(0) != poly[poly.size()-1] );
|
||||
eigen_assert( poly.size() > 1 );
|
||||
if(poly.size() > 2 )
|
||||
{
|
||||
internal::companion<Scalar,Deg_> companion( poly );
|
||||
companion.balance();
|
||||
m_eigenSolver.compute( companion.denseMatrix() );
|
||||
m_roots = m_eigenSolver.eigenvalues();
|
||||
// cleanup noise in imaginary part of real roots:
|
||||
// if the imaginary part is rather small compared to the real part
|
||||
// and that cancelling the imaginary part yield a smaller evaluation,
|
||||
// then it's safe to keep the real part only.
|
||||
RealScalar coarse_prec = RealScalar(std::pow(4,poly.size()+1))*NumTraits<RealScalar>::epsilon();
|
||||
for(Index i = 0; i<m_roots.size(); ++i)
|
||||
{
|
||||
if( internal::isMuchSmallerThan(numext::abs(numext::imag(m_roots[i])),
|
||||
numext::abs(numext::real(m_roots[i])),
|
||||
coarse_prec) )
|
||||
{
|
||||
ComplexScalar as_real_root = ComplexScalar(numext::real(m_roots[i]));
|
||||
if( numext::abs(poly_eval(poly, as_real_root))
|
||||
<= numext::abs(poly_eval(poly, m_roots[i])))
|
||||
{
|
||||
m_roots[i] = as_real_root;
|
||||
}
|
||||
public:
|
||||
/** Computes the complex roots of a new polynomial. */
|
||||
template <typename OtherPolynomial>
|
||||
void compute(const OtherPolynomial& poly) {
|
||||
eigen_assert(Scalar(0) != poly[poly.size() - 1]);
|
||||
eigen_assert(poly.size() > 1);
|
||||
if (poly.size() > 2) {
|
||||
internal::companion<Scalar, Deg_> companion(poly);
|
||||
companion.balance();
|
||||
m_eigenSolver.compute(companion.denseMatrix());
|
||||
m_roots = m_eigenSolver.eigenvalues();
|
||||
// cleanup noise in imaginary part of real roots:
|
||||
// if the imaginary part is rather small compared to the real part
|
||||
// and that cancelling the imaginary part yield a smaller evaluation,
|
||||
// then it's safe to keep the real part only.
|
||||
RealScalar coarse_prec = RealScalar(std::pow(4, poly.size() + 1)) * NumTraits<RealScalar>::epsilon();
|
||||
for (Index i = 0; i < m_roots.size(); ++i) {
|
||||
if (internal::isMuchSmallerThan(numext::abs(numext::imag(m_roots[i])), numext::abs(numext::real(m_roots[i])),
|
||||
coarse_prec)) {
|
||||
ComplexScalar as_real_root = ComplexScalar(numext::real(m_roots[i]));
|
||||
if (numext::abs(poly_eval(poly, as_real_root)) <= numext::abs(poly_eval(poly, m_roots[i]))) {
|
||||
m_roots[i] = as_real_root;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(poly.size () == 2)
|
||||
{
|
||||
m_roots.resize(1);
|
||||
m_roots[0] = -poly[0]/poly[1];
|
||||
}
|
||||
} else if (poly.size() == 2) {
|
||||
m_roots.resize(1);
|
||||
m_roots[0] = -poly[0] / poly[1];
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
template< typename OtherPolynomial >
|
||||
inline PolynomialSolver( const OtherPolynomial& poly ){
|
||||
compute( poly ); }
|
||||
public:
|
||||
template <typename OtherPolynomial>
|
||||
inline PolynomialSolver(const OtherPolynomial& poly) {
|
||||
compute(poly);
|
||||
}
|
||||
|
||||
inline PolynomialSolver(){}
|
||||
inline PolynomialSolver() {}
|
||||
|
||||
protected:
|
||||
using PS_Base::m_roots;
|
||||
EigenSolverType m_eigenSolver;
|
||||
protected:
|
||||
using PS_Base::m_roots;
|
||||
EigenSolverType m_eigenSolver;
|
||||
};
|
||||
|
||||
template <typename Scalar_>
|
||||
class PolynomialSolver<Scalar_, 1> : public PolynomialSolverBase<Scalar_, 1> {
|
||||
public:
|
||||
typedef PolynomialSolverBase<Scalar_, 1> PS_Base;
|
||||
EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES(PS_Base)
|
||||
|
||||
template< typename Scalar_ >
|
||||
class PolynomialSolver<Scalar_,1> : public PolynomialSolverBase<Scalar_,1>
|
||||
{
|
||||
public:
|
||||
typedef PolynomialSolverBase<Scalar_,1> PS_Base;
|
||||
EIGEN_POLYNOMIAL_SOLVER_BASE_INHERITED_TYPES( PS_Base )
|
||||
public:
|
||||
/** Computes the complex roots of a new polynomial. */
|
||||
template <typename OtherPolynomial>
|
||||
void compute(const OtherPolynomial& poly) {
|
||||
eigen_assert(poly.size() == 2);
|
||||
eigen_assert(Scalar(0) != poly[1]);
|
||||
m_roots[0] = -poly[0] / poly[1];
|
||||
}
|
||||
|
||||
public:
|
||||
/** Computes the complex roots of a new polynomial. */
|
||||
template< typename OtherPolynomial >
|
||||
void compute( const OtherPolynomial& poly )
|
||||
{
|
||||
eigen_assert( poly.size() == 2 );
|
||||
eigen_assert( Scalar(0) != poly[1] );
|
||||
m_roots[0] = -poly[0]/poly[1];
|
||||
}
|
||||
public:
|
||||
template <typename OtherPolynomial>
|
||||
inline PolynomialSolver(const OtherPolynomial& poly) {
|
||||
compute(poly);
|
||||
}
|
||||
|
||||
public:
|
||||
template< typename OtherPolynomial >
|
||||
inline PolynomialSolver( const OtherPolynomial& poly ){
|
||||
compute( poly ); }
|
||||
inline PolynomialSolver() {}
|
||||
|
||||
inline PolynomialSolver(){}
|
||||
|
||||
protected:
|
||||
using PS_Base::m_roots;
|
||||
protected:
|
||||
using PS_Base::m_roots;
|
||||
};
|
||||
|
||||
} // end namespace Eigen
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_POLYNOMIAL_SOLVER_H
|
||||
#endif // EIGEN_POLYNOMIAL_SOLVER_H
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
namespace Eigen {
|
||||
|
||||
/** \ingroup Polynomials_Module
|
||||
* \returns the evaluation of the polynomial at x using Horner algorithm.
|
||||
@@ -27,12 +27,11 @@ namespace Eigen {
|
||||
* \f$ |x| \le 1 \f$
|
||||
*/
|
||||
template <typename Polynomials, typename T>
|
||||
inline
|
||||
T poly_eval_horner( const Polynomials& poly, const T& x )
|
||||
{
|
||||
T val=poly[poly.size()-1];
|
||||
for(DenseIndex i=poly.size()-2; i>=0; --i ){
|
||||
val = val*x + poly[i]; }
|
||||
inline T poly_eval_horner(const Polynomials& poly, const T& x) {
|
||||
T val = poly[poly.size() - 1];
|
||||
for (DenseIndex i = poly.size() - 2; i >= 0; --i) {
|
||||
val = val * x + poly[i];
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -45,21 +44,19 @@ T poly_eval_horner( const Polynomials& poly, const T& x )
|
||||
* \param[in] x : the value to evaluate the polynomial at.
|
||||
*/
|
||||
template <typename Polynomials, typename T>
|
||||
inline
|
||||
T poly_eval( const Polynomials& poly, const T& x )
|
||||
{
|
||||
inline T poly_eval(const Polynomials& poly, const T& x) {
|
||||
typedef typename NumTraits<T>::Real Real;
|
||||
|
||||
if( numext::abs2( x ) <= Real(1) ){
|
||||
return poly_eval_horner( poly, x ); }
|
||||
else
|
||||
{
|
||||
T val=poly[0];
|
||||
T inv_x = T(1)/x;
|
||||
for( DenseIndex i=1; i<poly.size(); ++i ){
|
||||
val = val*inv_x + poly[i]; }
|
||||
if (numext::abs2(x) <= Real(1)) {
|
||||
return poly_eval_horner(poly, x);
|
||||
} else {
|
||||
T val = poly[0];
|
||||
T inv_x = T(1) / x;
|
||||
for (DenseIndex i = 1; i < poly.size(); ++i) {
|
||||
val = val * inv_x + poly[i];
|
||||
}
|
||||
|
||||
return numext::pow(x,(T)(poly.size()-1)) * val;
|
||||
return numext::pow(x, (T)(poly.size() - 1)) * val;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,19 +71,18 @@ T poly_eval( const Polynomials& poly, const T& x )
|
||||
* the leading coefficient of the input polynomial poly must be non zero
|
||||
*/
|
||||
template <typename Polynomial>
|
||||
inline
|
||||
typename NumTraits<typename Polynomial::Scalar>::Real cauchy_max_bound( const Polynomial& poly )
|
||||
{
|
||||
inline typename NumTraits<typename Polynomial::Scalar>::Real cauchy_max_bound(const Polynomial& poly) {
|
||||
using std::abs;
|
||||
typedef typename Polynomial::Scalar Scalar;
|
||||
typedef typename NumTraits<Scalar>::Real Real;
|
||||
|
||||
eigen_assert( Scalar(0) != poly[poly.size()-1] );
|
||||
const Scalar inv_leading_coeff = Scalar(1)/poly[poly.size()-1];
|
||||
eigen_assert(Scalar(0) != poly[poly.size() - 1]);
|
||||
const Scalar inv_leading_coeff = Scalar(1) / poly[poly.size() - 1];
|
||||
Real cb(0);
|
||||
|
||||
for( DenseIndex i=0; i<poly.size()-1; ++i ){
|
||||
cb += abs(poly[i]*inv_leading_coeff); }
|
||||
for (DenseIndex i = 0; i < poly.size() - 1; ++i) {
|
||||
cb += abs(poly[i] * inv_leading_coeff);
|
||||
}
|
||||
return cb + Real(1);
|
||||
}
|
||||
|
||||
@@ -97,23 +93,25 @@ typename NumTraits<typename Polynomial::Scalar>::Real cauchy_max_bound( const Po
|
||||
* e.g. \f$ 1 + 3x^2 \f$ is stored as a vector \f$ [ 1, 0, 3 ] \f$.
|
||||
*/
|
||||
template <typename Polynomial>
|
||||
inline
|
||||
typename NumTraits<typename Polynomial::Scalar>::Real cauchy_min_bound( const Polynomial& poly )
|
||||
{
|
||||
inline typename NumTraits<typename Polynomial::Scalar>::Real cauchy_min_bound(const Polynomial& poly) {
|
||||
using std::abs;
|
||||
typedef typename Polynomial::Scalar Scalar;
|
||||
typedef typename NumTraits<Scalar>::Real Real;
|
||||
|
||||
DenseIndex i=0;
|
||||
while( i<poly.size()-1 && Scalar(0) == poly(i) ){ ++i; }
|
||||
if( poly.size()-1 == i ){
|
||||
return Real(1); }
|
||||
DenseIndex i = 0;
|
||||
while (i < poly.size() - 1 && Scalar(0) == poly(i)) {
|
||||
++i;
|
||||
}
|
||||
if (poly.size() - 1 == i) {
|
||||
return Real(1);
|
||||
}
|
||||
|
||||
const Scalar inv_min_coeff = Scalar(1)/poly[i];
|
||||
const Scalar inv_min_coeff = Scalar(1) / poly[i];
|
||||
Real cb(1);
|
||||
for( DenseIndex j=i+1; j<poly.size(); ++j ){
|
||||
cb += abs(poly[j]*inv_min_coeff); }
|
||||
return Real(1)/cb;
|
||||
for (DenseIndex j = i + 1; j < poly.size(); ++j) {
|
||||
cb += abs(poly[j] * inv_min_coeff);
|
||||
}
|
||||
return Real(1) / cb;
|
||||
}
|
||||
|
||||
/** \ingroup Polynomials_Module
|
||||
@@ -127,20 +125,20 @@ typename NumTraits<typename Polynomial::Scalar>::Real cauchy_min_bound( const Po
|
||||
* e.g. \f$ 3 + x^2 \f$ is stored as a vector \f$ [ 3, 0, 1 ] \f$.
|
||||
*/
|
||||
template <typename RootVector, typename Polynomial>
|
||||
void roots_to_monicPolynomial( const RootVector& rv, Polynomial& poly )
|
||||
{
|
||||
|
||||
void roots_to_monicPolynomial(const RootVector& rv, Polynomial& poly) {
|
||||
typedef typename Polynomial::Scalar Scalar;
|
||||
|
||||
poly.setZero( rv.size()+1 );
|
||||
poly[0] = -rv[0]; poly[1] = Scalar(1);
|
||||
for( DenseIndex i=1; i< rv.size(); ++i )
|
||||
{
|
||||
for( DenseIndex j=i+1; j>0; --j ){ poly[j] = poly[j-1] - rv[i]*poly[j]; }
|
||||
poly[0] = -rv[i]*poly[0];
|
||||
poly.setZero(rv.size() + 1);
|
||||
poly[0] = -rv[0];
|
||||
poly[1] = Scalar(1);
|
||||
for (DenseIndex i = 1; i < rv.size(); ++i) {
|
||||
for (DenseIndex j = i + 1; j > 0; --j) {
|
||||
poly[j] = poly[j - 1] - rv[i] * poly[j];
|
||||
}
|
||||
poly[0] = -rv[i] * poly[0];
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace Eigen
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_POLYNOMIAL_UTILS_H
|
||||
#endif // EIGEN_POLYNOMIAL_UTILS_H
|
||||
|
||||
Reference in New Issue
Block a user