Apply clang-format

This commit is contained in:
Tobias Wood
2023-11-29 11:12:48 +00:00
parent 9ea520fc45
commit f38e16c193
534 changed files with 103368 additions and 116934 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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