Replace atanh with atanh2

This commit is contained in:
Chen-Pang He 2012-08-27 21:43:41 +01:00
parent ebe511334f
commit b55d260ada
3 changed files with 79 additions and 72 deletions

View File

@ -228,15 +228,15 @@ const MatrixPowerReturnValue<Derived, ExponentType> MatrixBase<Derived>::pow(con
\endcode \endcode
\param[in] M base of the matrix power, should be a square matrix. \param[in] M base of the matrix power, should be a square matrix.
\param[in] p exponent of the matrix power, should be an integer or \param[in] p exponent of the matrix power, should be real.
the same type as the real scalar in \p M.
The matrix power \f$ M^p \f$ is defined as \f$ \exp(p \log(M)) \f$, The matrix power \f$ M^p \f$ is defined as \f$ \exp(p \log(M)) \f$,
where exp denotes the matrix exponential, and log denotes the matrix where exp denotes the matrix exponential, and log denotes the matrix
logarithm. logarithm.
The matrix \f$ M \f$ should meet the conditions to be an argument of The matrix \f$ M \f$ should meet the conditions to be an argument of
matrix logarithm. matrix logarithm. If \p p is neither an integer nor the real scalar
type of \p M, it is casted into the real scalar type of \p M.
This function computes the matrix logarithm using the This function computes the matrix logarithm using the
Schur-Pad&eacute; algorithm as implemented by MatrixBase::pow(). Schur-Pad&eacute; algorithm as implemented by MatrixBase::pow().

View File

@ -51,7 +51,7 @@ private:
void compute2x2(const MatrixType& A, MatrixType& result); void compute2x2(const MatrixType& A, MatrixType& result);
void computeBig(const MatrixType& A, MatrixType& result); void computeBig(const MatrixType& A, MatrixType& result);
static Scalar atanh(Scalar x); static Scalar atanh2(Scalar y, Scalar x);
int getPadeDegree(float normTminusI); int getPadeDegree(float normTminusI);
int getPadeDegree(double normTminusI); int getPadeDegree(double normTminusI);
int getPadeDegree(long double normTminusI); int getPadeDegree(long double normTminusI);
@ -93,16 +93,18 @@ MatrixType MatrixLogarithmAtomic<MatrixType>::compute(const MatrixType& A)
return result; return result;
} }
/** \brief Compute atanh (inverse hyperbolic tangent). */ /** \brief Compute atanh (inverse hyperbolic tangent) for \f$ y / x \f$. */
template <typename MatrixType> template <typename MatrixType>
typename MatrixType::Scalar MatrixLogarithmAtomic<MatrixType>::atanh(typename MatrixType::Scalar x) typename MatrixType::Scalar MatrixLogarithmAtomic<MatrixType>::atanh2(Scalar y, Scalar x)
{ {
using std::abs; using std::abs;
using std::sqrt; using std::sqrt;
if (abs(x) > sqrt(NumTraits<Scalar>::epsilon()))
return Scalar(0.5) * log((Scalar(1) + x) / (Scalar(1) - x)); Scalar z = y / x;
if (abs(z) > sqrt(NumTraits<Scalar>::epsilon()))
return Scalar(0.5) * log((x + y) / (x - y));
else else
return x + x*x*x / Scalar(3); return z + z*z*z / Scalar(3);
} }
/** \brief Compute logarithm of 2x2 triangular matrix. */ /** \brief Compute logarithm of 2x2 triangular matrix. */
@ -128,8 +130,8 @@ void MatrixLogarithmAtomic<MatrixType>::compute2x2(const MatrixType& A, MatrixTy
} else { } else {
// computation in previous branch is inaccurate if A(1,1) \approx A(0,0) // computation in previous branch is inaccurate if A(1,1) \approx A(0,0)
int unwindingNumber = static_cast<int>(ceil((imag(logA11 - logA00) - M_PI) / (2*M_PI))); int unwindingNumber = static_cast<int>(ceil((imag(logA11 - logA00) - M_PI) / (2*M_PI)));
Scalar z = (A(1,1) - A(0,0)) / (A(1,1) + A(0,0)); Scalar y = A(1,1) - A(0,0), x = A(1,1) + A(0,0);
result(0,1) = A(0,1) * (Scalar(2) * atanh(z) + Scalar(0,2*M_PI*unwindingNumber)) / (A(1,1) - A(0,0)); result(0,1) = A(0,1) * (Scalar(2) * atanh2(y,x) + Scalar(0,2*M_PI*unwindingNumber)) / y;
} }
} }

View File

@ -23,14 +23,29 @@ namespace Eigen {
* *
* \tparam MatrixType type of the base, expected to be an instantiation * \tparam MatrixType type of the base, expected to be an instantiation
* of the Matrix class template. * of the Matrix class template.
* \tparam RealScalar type of the exponent, a real scalar. * \tparam ExponentType type of the exponent, a real scalar.
* \tparam PlainObject type of the multiplier. * \tparam PlainObject type of the multiplier.
* \tparam IsInteger used internally to select correct specialization. * \tparam IsInteger used internally to select correct specialization.
*/ */
template <typename MatrixType, typename RealScalar, typename PlainObject = MatrixType, template <typename MatrixType, typename ExponentType, typename PlainObject = MatrixType,
int IsInteger = NumTraits<RealScalar>::IsInteger> int IsInteger = NumTraits<ExponentType>::IsInteger>
class MatrixPower class MatrixPower
{ {
private:
typedef internal::traits<MatrixType> Traits;
static const int Rows = Traits::RowsAtCompileTime;
static const int Cols = Traits::ColsAtCompileTime;
static const int Options = Traits::Options;
static const int MaxRows = Traits::MaxRowsAtCompileTime;
static const int MaxCols = Traits::MaxColsAtCompileTime;
typedef typename MatrixType::Scalar Scalar;
typedef typename MatrixType::RealScalar RealScalar;
typedef std::complex<RealScalar> ComplexScalar;
typedef typename MatrixType::Index Index;
typedef Matrix<ComplexScalar, Rows, Cols, Options, MaxRows, MaxCols> ComplexMatrix;
typedef Array<ComplexScalar, Rows, 1, ColMajor, MaxRows> ComplexArray;
public: public:
/** /**
* \brief Constructor. * \brief Constructor.
@ -39,7 +54,7 @@ class MatrixPower
* \param[in] p the exponent of the matrix power. * \param[in] p the exponent of the matrix power.
* \param[in] b the multiplier. * \param[in] b the multiplier.
*/ */
MatrixPower(const MatrixType& A, const RealScalar& p, const PlainObject& b) : MatrixPower(const MatrixType& A, RealScalar p, const PlainObject& b) :
m_A(A), m_A(A),
m_p(p), m_p(p),
m_b(b), m_b(b),
@ -55,19 +70,6 @@ class MatrixPower
template <typename ResultType> void compute(ResultType& result); template <typename ResultType> void compute(ResultType& result);
private: private:
typedef internal::traits<MatrixType> Traits;
static const int Rows = Traits::RowsAtCompileTime;
static const int Cols = Traits::ColsAtCompileTime;
static const int Options = Traits::Options;
static const int MaxRows = Traits::MaxRowsAtCompileTime;
static const int MaxCols = Traits::MaxColsAtCompileTime;
typedef typename MatrixType::Scalar Scalar;
typedef std::complex<RealScalar> ComplexScalar;
typedef typename MatrixType::Index Index;
typedef Matrix<ComplexScalar, Rows, Cols, Options, MaxRows, MaxCols> ComplexMatrix;
typedef Array<ComplexScalar, Rows, 1, ColMajor, MaxRows> ComplexArray;
/** /**
* \brief Compute the matrix power. * \brief Compute the matrix power.
* *
@ -112,8 +114,8 @@ class MatrixPower
*/ */
void getFractionalExponent(); void getFractionalExponent();
/** \brief Compute atanh (inverse hyperbolic tangent). */ /** \brief Compute atanh (inverse hyperbolic tangent) for \f$ y / x \f$. */
ComplexScalar atanh(const ComplexScalar& x); ComplexScalar atanh2(const ComplexScalar& y, const ComplexScalar& x);
/** \brief Compute power of 2x2 triangular matrix. */ /** \brief Compute power of 2x2 triangular matrix. */
void compute2x2(const RealScalar& p); void compute2x2(const RealScalar& p);
@ -237,9 +239,9 @@ class MatrixPower<MatrixType, IntExponent, PlainObject, 1>
/******* Specialized for real exponents *******/ /******* Specialized for real exponents *******/
template <typename MatrixType, typename RealScalar, typename PlainObject, int IsInteger> template <typename MatrixType, typename ExponentType, typename PlainObject, int IsInteger>
template <typename ResultType> template <typename ResultType>
void MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::compute(ResultType& result) void MatrixPower<MatrixType,ExponentType,PlainObject,IsInteger>::compute(ResultType& result)
{ {
using std::floor; using std::floor;
using std::pow; using std::pow;
@ -264,9 +266,9 @@ void MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::compute(ResultTyp
} }
} }
template <typename MatrixType, typename RealScalar, typename PlainObject, int IsInteger> template <typename MatrixType, typename ExponentType, typename PlainObject, int IsInteger>
template <typename ResultType> template <typename ResultType>
void MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::computeIntPower(ResultType& result) void MatrixPower<MatrixType,ExponentType,PlainObject,IsInteger>::computeIntPower(ResultType& result)
{ {
if (m_dimb > m_dimA) { if (m_dimb > m_dimA) {
MatrixType tmp = MatrixType::Identity(m_A.rows(), m_A.cols()); MatrixType tmp = MatrixType::Identity(m_A.rows(), m_A.cols());
@ -278,9 +280,9 @@ void MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::computeIntPower(R
} }
} }
template <typename MatrixType, typename RealScalar, typename PlainObject, int IsInteger> template <typename MatrixType, typename ExponentType, typename PlainObject, int IsInteger>
template <typename ResultType> template <typename ResultType>
void MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::computeChainProduct(ResultType& result) void MatrixPower<MatrixType,ExponentType,PlainObject,IsInteger>::computeChainProduct(ResultType& result)
{ {
using std::frexp; using std::frexp;
using std::ldexp; using std::ldexp;
@ -312,8 +314,8 @@ void MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::computeChainProdu
result = m_tmp * result; result = m_tmp * result;
} }
template <typename MatrixType, typename RealScalar, typename PlainObject, int IsInteger> template <typename MatrixType, typename ExponentType, typename PlainObject, int IsInteger>
int MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::computeCost(RealScalar p) int MatrixPower<MatrixType,ExponentType,PlainObject,IsInteger>::computeCost(RealScalar p)
{ {
using std::frexp; using std::frexp;
using std::ldexp; using std::ldexp;
@ -326,25 +328,25 @@ int MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::computeCost(RealSc
return cost; return cost;
} }
template <typename MatrixType, typename RealScalar, typename PlainObject, int IsInteger> template <typename MatrixType, typename ExponentType, typename PlainObject, int IsInteger>
template <typename ResultType> template <typename ResultType>
void MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::partialPivLuSolve(ResultType& result, RealScalar p) void MatrixPower<MatrixType,ExponentType,PlainObject,IsInteger>::partialPivLuSolve(ResultType& result, RealScalar p)
{ {
const PartialPivLU<MatrixType> Asolver(m_A); const PartialPivLU<MatrixType> Asolver(m_A);
for (; p >= RealScalar(1); p--) for (; p >= RealScalar(1); p--)
result = Asolver.solve(result); result = Asolver.solve(result);
} }
template <typename MatrixType, typename RealScalar, typename PlainObject, int IsInteger> template <typename MatrixType, typename ExponentType, typename PlainObject, int IsInteger>
void MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::computeSchurDecomposition() void MatrixPower<MatrixType,ExponentType,PlainObject,IsInteger>::computeSchurDecomposition()
{ {
const ComplexSchur<MatrixType> schurOfA(m_A); const ComplexSchur<MatrixType> schurOfA(m_A);
m_T = schurOfA.matrixT(); m_T = schurOfA.matrixT();
m_U = schurOfA.matrixU(); m_U = schurOfA.matrixU();
} }
template <typename MatrixType, typename RealScalar, typename PlainObject, int IsInteger> template <typename MatrixType, typename ExponentType, typename PlainObject, int IsInteger>
void MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::getFractionalExponent() void MatrixPower<MatrixType,ExponentType,PlainObject,IsInteger>::getFractionalExponent()
{ {
using std::pow; using std::pow;
@ -373,21 +375,24 @@ void MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::getFractionalExpo
} }
} }
template <typename MatrixType, typename RealScalar, typename PlainObject, int IsInteger> template <typename MatrixType, typename ExponentType, typename PlainObject, int IsInteger>
std::complex<RealScalar> MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::atanh(const ComplexScalar& x) std::complex<typename MatrixType::RealScalar>
MatrixPower<MatrixType,ExponentType,PlainObject,IsInteger>::atanh2(const ComplexScalar& y, const ComplexScalar& x)
{ {
using std::abs; using std::abs;
using std::log; using std::log;
using std::sqrt; using std::sqrt;
if (abs(x) > sqrt(NumTraits<RealScalar>::epsilon())) const ComplexScalar z = y / x;
return RealScalar(0.5) * log((RealScalar(1) + x) / (RealScalar(1) - x));
if (abs(z) > sqrt(NumTraits<RealScalar>::epsilon()))
return RealScalar(0.5) * log((x + y) / (x - y));
else else
return x + x*x*x / RealScalar(3); return z + z*z*z / RealScalar(3);
} }
template <typename MatrixType, typename RealScalar, typename PlainObject, int IsInteger> template <typename MatrixType, typename ExponentType, typename PlainObject, int IsInteger>
void MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::compute2x2(const RealScalar& p) void MatrixPower<MatrixType,ExponentType,PlainObject,IsInteger>::compute2x2(const RealScalar& p)
{ {
using std::abs; using std::abs;
using std::ceil; using std::ceil;
@ -414,15 +419,15 @@ void MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::compute2x2(const
else { else {
// computation in previous branch is inaccurate if abs(m_T(j,j)) \approx abs(m_T(i,i)) // computation in previous branch is inaccurate if abs(m_T(j,j)) \approx abs(m_T(i,i))
unwindingNumber = static_cast<int>(ceil((imag(m_logTdiag[j] - m_logTdiag[i]) - M_PI) / (2 * M_PI))); unwindingNumber = static_cast<int>(ceil((imag(m_logTdiag[j] - m_logTdiag[i]) - M_PI) / (2 * M_PI)));
w = atanh((m_T(j,j) - m_T(i,i)) / (m_T(j,j) + m_T(i,i))) + ComplexScalar(0, M_PI * unwindingNumber); w = atanh2(m_T(j,j) - m_T(i,i), m_T(j,j) + m_T(i,i)) + ComplexScalar(0, M_PI * unwindingNumber);
m_fT(i,j) = m_T(i,j) * RealScalar(2) * exp(RealScalar(0.5) * p * (m_logTdiag[j] + m_logTdiag[i])) * m_fT(i,j) = m_T(i,j) * RealScalar(2) * exp(RealScalar(0.5) * p * (m_logTdiag[j] + m_logTdiag[i])) *
sinh(p * w) / (m_T(j,j) - m_T(i,i)); sinh(p * w) / (m_T(j,j) - m_T(i,i));
} }
} }
} }
template <typename MatrixType, typename RealScalar, typename PlainObject, int IsInteger> template <typename MatrixType, typename ExponentType, typename PlainObject, int IsInteger>
void MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::computeBig() void MatrixPower<MatrixType,ExponentType,PlainObject,IsInteger>::computeBig()
{ {
using std::ldexp; using std::ldexp;
const int digits = std::numeric_limits<RealScalar>::digits; const int digits = std::numeric_limits<RealScalar>::digits;
@ -458,8 +463,8 @@ void MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::computeBig()
compute2x2(m_pfrac); compute2x2(m_pfrac);
} }
template <typename MatrixType, typename RealScalar, typename PlainObject, int IsInteger> template <typename MatrixType, typename ExponentType, typename PlainObject, int IsInteger>
inline int MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::getPadeDegree(float normIminusT) inline int MatrixPower<MatrixType,ExponentType,PlainObject,IsInteger>::getPadeDegree(float normIminusT)
{ {
const float maxNormForPade[] = { 2.7996156e-1f /* degree = 3 */ , 4.3268868e-1f }; const float maxNormForPade[] = { 2.7996156e-1f /* degree = 3 */ , 4.3268868e-1f };
int degree = 3; int degree = 3;
@ -469,8 +474,8 @@ inline int MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::getPadeDegr
return degree; return degree;
} }
template <typename MatrixType, typename RealScalar, typename PlainObject, int IsInteger> template <typename MatrixType, typename ExponentType, typename PlainObject, int IsInteger>
inline int MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::getPadeDegree(double normIminusT) inline int MatrixPower<MatrixType,ExponentType,PlainObject,IsInteger>::getPadeDegree(double normIminusT)
{ {
const double maxNormForPade[] = { 1.882832775783710e-2 /* degree = 3 */ , 6.036100693089536e-2, const double maxNormForPade[] = { 1.882832775783710e-2 /* degree = 3 */ , 6.036100693089536e-2,
1.239372725584857e-1, 1.998030690604104e-1, 2.787629930861592e-1 }; 1.239372725584857e-1, 1.998030690604104e-1, 2.787629930861592e-1 };
@ -481,8 +486,8 @@ inline int MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::getPadeDegr
return degree; return degree;
} }
template <typename MatrixType, typename RealScalar, typename PlainObject, int IsInteger> template <typename MatrixType, typename ExponentType, typename PlainObject, int IsInteger>
inline int MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::getPadeDegree(long double normIminusT) inline int MatrixPower<MatrixType,ExponentType,PlainObject,IsInteger>::getPadeDegree(long double normIminusT)
{ {
#if LDBL_MANT_DIG == 53 #if LDBL_MANT_DIG == 53
const int maxPadeDegree = 7; const int maxPadeDegree = 7;
@ -514,8 +519,8 @@ inline int MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::getPadeDegr
break; break;
return degree; return degree;
} }
template <typename MatrixType, typename RealScalar, typename PlainObject, int IsInteger> template <typename MatrixType, typename ExponentType, typename PlainObject, int IsInteger>
void MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::computePade(const int& degree, const ComplexMatrix& IminusT) void MatrixPower<MatrixType,ExponentType,PlainObject,IsInteger>::computePade(const int& degree, const ComplexMatrix& IminusT)
{ {
int i = degree << 1; int i = degree << 1;
m_fT = coeff(i) * IminusT; m_fT = coeff(i) * IminusT;
@ -526,8 +531,8 @@ void MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::computePade(const
m_fT += ComplexMatrix::Identity(m_A.rows(), m_A.cols()); m_fT += ComplexMatrix::Identity(m_A.rows(), m_A.cols());
} }
template <typename MatrixType, typename RealScalar, typename PlainObject, int IsInteger> template <typename MatrixType, typename ExponentType, typename PlainObject, int IsInteger>
inline RealScalar MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::coeff(const int& i) inline typename MatrixType::RealScalar MatrixPower<MatrixType,ExponentType,PlainObject,IsInteger>::coeff(const int& i)
{ {
if (i == 1) if (i == 1)
return -m_pfrac; return -m_pfrac;
@ -537,13 +542,13 @@ inline RealScalar MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::coef
return (m_pfrac - RealScalar(i >> 1)) / RealScalar(i-1 << 1); return (m_pfrac - RealScalar(i >> 1)) / RealScalar(i-1 << 1);
} }
template <typename MatrixType, typename RealScalar, typename PlainObject, int IsInteger> template <typename MatrixType, typename ExponentType, typename PlainObject, int IsInteger>
void MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::computeTmp(RealScalar) void MatrixPower<MatrixType,ExponentType,PlainObject,IsInteger>::computeTmp(RealScalar)
{ m_tmp = (m_U * m_fT * m_U.adjoint()).real(); } { m_tmp = (m_U * m_fT * m_U.adjoint()).real(); }
template <typename MatrixType, typename RealScalar, typename PlainObject, int IsInteger> template <typename MatrixType, typename ExponentType, typename PlainObject, int IsInteger>
void MatrixPower<MatrixType,RealScalar,PlainObject,IsInteger>::computeTmp(ComplexScalar) void MatrixPower<MatrixType,ExponentType,PlainObject,IsInteger>::computeTmp(ComplexScalar)
{ m_tmp = (m_U * m_fT * m_U.adjoint()).eval(); } { m_tmp = m_U * m_fT * m_U.adjoint(); }
/******* Specialized for integral exponents *******/ /******* Specialized for integral exponents *******/