diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 7b8850eb7..e12a6763e 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -163,8 +163,8 @@ template class MatrixBase template Derived& lazyAssign(const ProductBase& other); - template - Derived& lazyAssign(const MatrixPowerProductBase& other); + template + Derived& lazyAssign(const MatrixPowerProduct& other); #endif // not EIGEN_PARSED_BY_DOXYGEN template diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index b114b3745..d6a814586 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -271,7 +271,7 @@ template class MatrixFunctionReturnValue; template class MatrixSquareRootReturnValue; template class MatrixLogarithmReturnValue; template class MatrixPowerReturnValue; -template class MatrixPowerProductBase; +template class MatrixPowerProduct; namespace internal { template diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixPower.h b/unsupported/Eigen/src/MatrixFunctions/MatrixPower.h index 3ac11979e..a618a536f 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixPower.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixPower.h @@ -12,7 +12,222 @@ namespace Eigen { -template class MatrixPowerEvaluator; +/** + * \ingroup MatrixFunctions_Module + * + * \brief Class for computing matrix powers. + * + * \tparam MatrixType type of the base, expected to be an instantiation + * of the Matrix class template. + * + * This class is capable of computing complex upper triangular matrices raised + * to an arbitrary real power. + */ +template +class MatrixPowerTriangular : public MatrixPowerBase,MatrixType> +{ + public: + EIGEN_MATRIX_POWER_PUBLIC_INTERFACE(MatrixPowerTriangular) + + /** + * \brief Constructor. + * + * \param[in] A the base of the matrix power. + * + * The class stores a reference to A, so it should not be changed + * (or destroyed) before evaluation. + */ + explicit MatrixPowerTriangular(const MatrixType& A) : Base(A,0), m_T(Base::m_A) + { } + + #ifdef EIGEN_PARSED_BY_DOXYGEN + /** + * \brief Returns the matrix power. + * + * \param[in] p exponent, a real scalar. + * \return The expression \f$ A^p \f$, where A is specified in the + * constructor. + */ + const MatrixPowerBaseReturnValue,MatrixType> operator()(RealScalar p); + #endif + + /** + * \brief Compute the matrix power. + * + * \param[in] p exponent, a real scalar. + * \param[out] res \f$ A^p \f$ where A is specified in the + * constructor. + */ + void compute(MatrixType& res, RealScalar p); + + /** + * \brief Compute the matrix power multiplied by another matrix. + * + * \param[in] b a matrix with the same rows as A. + * \param[in] p exponent, a real scalar. + * \param[out] res \f$ A^p b \f$, where A is specified in the + * constructor. + */ + template + void compute(const Derived& b, ResultType& res, RealScalar p); + + private: + EIGEN_MATRIX_POWER_PROTECTED_MEMBERS(MatrixPowerTriangular) + + const TriangularView m_T; + + RealScalar modfAndInit(RealScalar, RealScalar*); + + template + void apply(const Derived&, ResultType&, bool&); + + template + void computeIntPower(ResultType&, RealScalar); + + template + void computeIntPower(const Derived&, ResultType&, RealScalar); + + template + void computeFracPower(ResultType&, RealScalar); +}; + +template +void MatrixPowerTriangular::compute(MatrixType& res, RealScalar p) +{ + switch (m_A.cols()) { + case 0: + break; + case 1: + res(0,0) = std::pow(m_T.coeff(0,0), p); + break; + default: + RealScalar intpart, x = modfAndInit(p, &intpart); + res = m_Id; + computeIntPower(res, intpart); + computeFracPower(res, x); + } +} + +template +template +void MatrixPowerTriangular::compute(const Derived& b, ResultType& res, RealScalar p) +{ + switch (m_A.cols()) { + case 0: + break; + case 1: + res = std::pow(m_T.coeff(0,0), p) * b; + break; + default: + RealScalar intpart, x = modfAndInit(p, &intpart); + computeIntPower(b, res, intpart); + computeFracPower(res, x); + } +} + +template +typename MatrixPowerTriangular::Base::RealScalar +MatrixPowerTriangular::modfAndInit(RealScalar x, RealScalar* intpart) +{ + *intpart = std::floor(x); + RealScalar res = x - *intpart; + + if (!m_conditionNumber && res) { + const RealArray absTdiag = m_A.diagonal().array().abs(); + m_conditionNumber = absTdiag.maxCoeff() / absTdiag.minCoeff(); + } + + if (res>RealScalar(0.5) && res>(1-res)*std::pow(m_conditionNumber,res)) { + --res; + ++*intpart; + } + return res; +} + +template +template +void MatrixPowerTriangular::apply(const Derived& b, ResultType& res, bool& init) +{ + if (init) + res = m_tmp1.template triangularView() * res; + else { + init = true; + res.noalias() = m_tmp1.template triangularView() * b; + } +} + +template +template +void MatrixPowerTriangular::computeIntPower(ResultType& res, RealScalar p) +{ + RealScalar pp = std::abs(p); + + if (p<0) m_tmp1 = m_T.solve(m_Id); + else m_tmp1 = m_T; + + while (pp >= 1) { + if (std::fmod(pp, 2) >= 1) + res = m_tmp1.template triangularView() * res; + m_tmp1 = m_tmp1.template triangularView() * m_tmp1; + pp /= 2; + } +} + +template +template +void MatrixPowerTriangular::computeIntPower(const Derived& b, ResultType& res, RealScalar p) +{ + if (b.cols() >= m_A.cols()) { + m_tmp2 = m_Id; + computeIntPower(m_tmp2, p); + res.noalias() = m_tmp2.template triangularView() * b; + } + else { + RealScalar pp = std::abs(p); + int squarings, applyings = internal::binary_powering_cost(pp, &squarings); + bool init = false; + + if (p==0) { + res = b; + return; + } + else if (p>0) { + m_tmp1 = m_T; + } + else if (m_A.cols() > 2 && b.cols()*(pp-applyings) <= m_A.cols()*squarings) { + res = m_T.solve(b); + for (--pp; pp >= 1; --pp) + res = m_T.solve(res); + return; + } + else { + m_tmp1 = m_T.solve(m_Id); + } + + while (b.cols()*(pp-applyings) > m_A.cols()*squarings) { + if (std::fmod(pp, 2) >= 1) { + apply(b, res, init); + --applyings; + } + m_tmp1 = m_tmp1.template triangularView() * m_tmp1; + --squarings; + pp /= 2; + } + for (; pp >= 1; --pp) + apply(b, res, init); + } +} + +template +template +void MatrixPowerTriangular::computeFracPower(ResultType& res, RealScalar p) +{ + if (p) { + eigen_assert(m_conditionNumber); + MatrixPowerTriangularAtomic(m_A).compute(m_tmp1, p); + res = m_tmp1.template triangularView() * res; + } +} /** * \ingroup MatrixFunctions_Module @@ -44,18 +259,22 @@ class MatrixPower : public MatrixPowerBase,MatrixType> * * \param[in] A the base of the matrix power. * - * \warning Construct with a matrix, not a matrix expression! + * The class stores a reference to A, so it should not be changed + * (or destroyed) before evaluation. */ explicit MatrixPower(const MatrixType& A) : Base(A,0) { } + #ifdef EIGEN_PARSED_BY_DOXYGEN /** - * \brief Return the expression \f$ A^p \f$. + * \brief Returns the matrix power. * * \param[in] p exponent, a real scalar. + * \return The expression \f$ A^p \f$, where A is specified in the + * constructor. */ - const MatrixPowerEvaluator operator()(RealScalar p) - { return MatrixPowerEvaluator(*this, p); } + const MatrixPowerBaseReturnValue,MatrixType> operator()(RealScalar p); + #endif /** * \brief Compute the matrix power. @@ -242,31 +461,13 @@ void MatrixPower::computeFracPower(ResultType& res, RealScalar p) } } -template -class MatrixPowerMatrixProduct : public MatrixPowerProductBase,Lhs,Rhs> -{ - public: - EIGEN_MATRIX_POWER_PRODUCT_PUBLIC_INTERFACE(MatrixPowerMatrixProduct) +namespace internal { - MatrixPowerMatrixProduct(MatrixPower& pow, const Rhs& b, RealScalar p) : - m_pow(pow), - m_b(b), - m_p(p) - { } +template +struct traits > +{ typedef typename Derived::PlainObject ReturnType; }; - template - inline void evalTo(ResultType& res) const - { m_pow.compute(m_b, res, m_p); } - - Index rows() const { return m_pow.rows(); } - Index cols() const { return m_b.cols(); } - - private: - MatrixPower& m_pow; - const Rhs& m_b; - const RealScalar m_p; - MatrixPowerMatrixProduct& operator=(const MatrixPowerMatrixProduct&); -}; +} // namespace internal /** * \ingroup MatrixFunctions_Module @@ -316,10 +517,11 @@ class MatrixPowerReturnValue : public ReturnByValue - const MatrixPowerMatrixProduct operator*(const MatrixBase& b) const + const MatrixPowerProduct,PlainObject,OtherDerived> + operator*(const MatrixBase& b) const { MatrixPower Apow(m_A.eval()); - return MatrixPowerMatrixProduct(Apow, b.derived(), m_p); + return MatrixPowerProduct,PlainObject,OtherDerived>(Apow, b.derived(), m_p); } Index rows() const { return m_A.rows(); } @@ -331,52 +533,6 @@ class MatrixPowerReturnValue : public ReturnByValue -class MatrixPowerEvaluator : public ReturnByValue > -{ - public: - typedef typename MatrixType::RealScalar RealScalar; - typedef typename MatrixType::Index Index; - - MatrixPowerEvaluator(MatrixPower& pow, RealScalar p) : m_pow(pow), m_p(p) - { } - - template - inline void evalTo(ResultType& res) const - { m_pow.compute(res, m_p); } - - template - const MatrixPowerMatrixProduct operator*(const MatrixBase& b) const - { return MatrixPowerMatrixProduct(m_pow, b.derived(), m_p); } - - Index rows() const { return m_pow.rows(); } - Index cols() const { return m_pow.cols(); } - - private: - MatrixPower& m_pow; - const RealScalar m_p; - MatrixPowerEvaluator& operator=(const MatrixPowerEvaluator&); -}; - -namespace internal { -template -struct nested > -{ typedef typename MatrixPowerMatrixProduct::PlainObject const& type; }; - -template -struct traits > -{ typedef typename Derived::PlainObject ReturnType; }; - -template -struct traits > -{ typedef MatrixType ReturnType; }; - -template -struct traits > -: traits,Lhs,Rhs> > -{ }; -} // namespace internal - template const MatrixPowerReturnValue MatrixBase::pow(RealScalar p) const { return MatrixPowerReturnValue(derived(), p); } diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixPowerBase.h b/unsupported/Eigen/src/MatrixFunctions/MatrixPowerBase.h index 9616659ca..b67939039 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixPowerBase.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixPowerBase.h @@ -12,9 +12,171 @@ namespace Eigen { +#define EIGEN_MATRIX_POWER_PUBLIC_INTERFACE(Derived) \ + typedef MatrixPowerBase Base; \ + using Base::RowsAtCompileTime; \ + using Base::ColsAtCompileTime; \ + using Base::Options; \ + using Base::MaxRowsAtCompileTime; \ + using Base::MaxColsAtCompileTime; \ + typedef typename Base::Scalar Scalar; \ + typedef typename Base::RealScalar RealScalar; \ + typedef typename Base::RealArray RealArray; + +#define EIGEN_MATRIX_POWER_PROTECTED_MEMBERS(Derived) \ + using Base::m_A; \ + using Base::m_Id; \ + using Base::m_tmp1; \ + using Base::m_tmp2; \ + using Base::m_conditionNumber; + +template +class MatrixPowerBaseReturnValue : public ReturnByValue > +{ + public: + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + + MatrixPowerBaseReturnValue(Derived& pow, RealScalar p) : m_pow(pow), m_p(p) + { } + + template + inline void evalTo(ResultType& res) const + { m_pow.compute(res, m_p); } + + template + const MatrixPowerProduct operator*(const MatrixBase& b) const + { return MatrixPowerProduct(m_pow, b.derived(), m_p); } + + Index rows() const { return m_pow.rows(); } + Index cols() const { return m_pow.cols(); } + + private: + Derived& m_pow; + const RealScalar m_p; + MatrixPowerBaseReturnValue& operator=(const MatrixPowerBaseReturnValue&); +}; + +template +class MatrixPowerBase +{ + private: + Derived& derived() { return *static_cast(this); } + + public: + enum { + RowsAtCompileTime = MatrixType::RowsAtCompileTime, + ColsAtCompileTime = MatrixType::ColsAtCompileTime, + Options = MatrixType::Options, + MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime + }; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + + explicit MatrixPowerBase(const MatrixType& A, RealScalar cond) : + m_A(A), + m_Id(MatrixType::Identity(A.rows(),A.cols())), + m_conditionNumber(cond) + { eigen_assert(A.rows() == A.cols()); } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + const MatrixPowerBaseReturnValue operator()(RealScalar p) + { return MatrixPowerBaseReturnValue(derived(), p); } + #endif + + void compute(MatrixType& res, RealScalar p) + { derived().compute(res,p); } + + template + void compute(const OtherDerived& b, ResultType& res, RealScalar p) + { derived().compute(b,res,p); } + + Index rows() const { return m_A.rows(); } + Index cols() const { return m_A.cols(); } + + protected: + typedef Array RealArray; + + const MatrixType& m_A; + const MatrixType m_Id; + MatrixType m_tmp1, m_tmp2; + RealScalar m_conditionNumber; +}; + +template +class MatrixPowerProduct : public MatrixBase > +{ + public: + typedef MatrixBase > Base; + EIGEN_DENSE_PUBLIC_INTERFACE(MatrixPowerProduct) + + MatrixPowerProduct(Derived& pow, const Rhs& b, RealScalar p) : + m_pow(pow), + m_b(b), + m_p(p) + { eigen_assert(pow.cols() == b.rows()); } + + template + inline void evalTo(ResultType& res) const + { m_pow.compute(m_b, res, m_p); } + + inline Index rows() const { return m_pow.rows(); } + inline Index cols() const { return m_b.cols(); } + + private: + Derived& m_pow; + const Rhs& m_b; + const RealScalar m_p; +}; + +template +template +Derived& MatrixBase::lazyAssign(const MatrixPowerProduct& other) +{ + other.evalTo(derived()); + return derived(); +} + namespace internal { -template -struct recompose_complex_schur + +template +struct traits > +{ typedef MatrixType ReturnType; }; + +template +struct nested > +{ typedef typename MatrixPowerProduct::PlainObject const& type; }; + +template +struct traits > +{ + typedef MatrixXpr XprKind; + typedef typename remove_all<_Lhs>::type Lhs; + typedef typename remove_all<_Rhs>::type Rhs; + typedef typename remove_all >::type PlainObject; + typedef typename scalar_product_traits::ReturnType Scalar; + typedef typename promote_storage_type::StorageKind, + typename traits::StorageKind>::ret StorageKind; + typedef typename promote_index_type::Index, + typename traits::Index>::type Index; + + enum { + RowsAtCompileTime = traits::RowsAtCompileTime, + ColsAtCompileTime = traits::ColsAtCompileTime, + MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = traits::MaxColsAtCompileTime, + Flags = (MaxRowsAtCompileTime==1 ? RowMajorBit : 0) + | EvalBeforeNestingBit | EvalBeforeAssigningBit | NestByRefBit, + CoeffReadCost = 0 + }; +}; + +template struct recompose_complex_schur; + +template<> +struct recompose_complex_schur { template static inline void run(ResultType& res, const MatrixType& T, const MatrixType& U) @@ -22,7 +184,7 @@ struct recompose_complex_schur }; template<> -struct recompose_complex_schur<0> +struct recompose_complex_schur { template static inline void run(ResultType& res, const MatrixType& T, const MatrixType& U) @@ -109,10 +271,14 @@ inline int matrix_power_get_pade_degree(long double normIminusT) break; return degree; } + } // namespace internal +template::IsComplex> +class MatrixPowerTriangularAtomic; + template -class MatrixPowerTriangularAtomic +class MatrixPowerTriangularAtomic { private: enum { @@ -136,13 +302,13 @@ class MatrixPowerTriangularAtomic }; template -MatrixPowerTriangularAtomic::MatrixPowerTriangularAtomic(const MatrixType& T) : +MatrixPowerTriangularAtomic::MatrixPowerTriangularAtomic(const MatrixType& T) : m_T(T), m_Id(MatrixType::Identity(T.rows(), T.cols())) { eigen_assert(T.rows() == T.cols()); } template -void MatrixPowerTriangularAtomic::compute(MatrixType& res, RealScalar p) const +void MatrixPowerTriangularAtomic::compute(MatrixType& res, RealScalar p) const { switch (m_T.rows()) { case 0: @@ -159,7 +325,7 @@ void MatrixPowerTriangularAtomic::compute(MatrixType& res, RealScala } template -void MatrixPowerTriangularAtomic::computePade(int degree, const MatrixType& IminusT, MatrixType& res, +void MatrixPowerTriangularAtomic::computePade(int degree, const MatrixType& IminusT, MatrixType& res, RealScalar p) const { int i = degree<<1; @@ -172,7 +338,7 @@ void MatrixPowerTriangularAtomic::computePade(int degree, const Matr } template -void MatrixPowerTriangularAtomic::compute2x2(MatrixType& res, RealScalar p) const +void MatrixPowerTriangularAtomic::compute2x2(MatrixType& res, RealScalar p) const { using std::abs; using std::pow; @@ -198,7 +364,7 @@ void MatrixPowerTriangularAtomic::compute2x2(MatrixType& res, RealSc } template -void MatrixPowerTriangularAtomic::computeBig(MatrixType& res, RealScalar p) const +void MatrixPowerTriangularAtomic::computeBig(MatrixType& res, RealScalar p) const { const int digits = std::numeric_limits::digits; const RealScalar maxNormForPade = digits <= 24? 4.3386528e-1f: // sigle precision @@ -212,7 +378,7 @@ void MatrixPowerTriangularAtomic::computeBig(MatrixType& res, RealSc bool hasExtraSquareRoot=false; while (true) { - IminusT = MatrixType::Identity(m_T.rows(), m_T.cols()) - T; + IminusT = m_Id - T; normIminusT = IminusT.cwiseAbs().colwise().sum().maxCoeff(); if (normIminusT < maxNormForPade) { degree = internal::matrix_power_get_pade_degree(normIminusT); @@ -234,126 +400,6 @@ void MatrixPowerTriangularAtomic::computeBig(MatrixType& res, RealSc compute2x2(res, p); } -#define EIGEN_MATRIX_POWER_PUBLIC_INTERFACE(Derived) \ - typedef MatrixPowerBase Base; \ - using Base::RowsAtCompileTime; \ - using Base::ColsAtCompileTime; \ - using Base::Options; \ - using Base::MaxRowsAtCompileTime; \ - using Base::MaxColsAtCompileTime; \ - typedef typename Base::Scalar Scalar; \ - typedef typename Base::RealScalar RealScalar; \ - typedef typename Base::RealArray RealArray; - -#define EIGEN_MATRIX_POWER_PROTECTED_MEMBERS(Derived) \ - using Base::m_A; \ - using Base::m_Id; \ - using Base::m_tmp1; \ - using Base::m_tmp2; \ - using Base::m_conditionNumber; - -#define EIGEN_MATRIX_POWER_PRODUCT_PUBLIC_INTERFACE(Derived) \ - typedef MatrixPowerProductBase Base; \ - EIGEN_DENSE_PUBLIC_INTERFACE(Derived) - -namespace internal { -template -struct traits > -{ - typedef MatrixXpr XprKind; - typedef typename remove_all<_Lhs>::type Lhs; - typedef typename remove_all<_Rhs>::type Rhs; - typedef typename remove_all::type PlainObject; - typedef typename scalar_product_traits::ReturnType Scalar; - typedef typename promote_storage_type::StorageKind, - typename traits::StorageKind>::ret StorageKind; - typedef typename promote_index_type::Index, - typename traits::Index>::type Index; - - enum { - RowsAtCompileTime = traits::RowsAtCompileTime, - ColsAtCompileTime = traits::ColsAtCompileTime, - MaxRowsAtCompileTime = traits::MaxRowsAtCompileTime, - MaxColsAtCompileTime = traits::MaxColsAtCompileTime, - Flags = (MaxRowsAtCompileTime==1 ? RowMajorBit : 0) - | EvalBeforeNestingBit | EvalBeforeAssigningBit | NestByRefBit, - CoeffReadCost = 0 - }; -}; -} // namespace internal - -template -class MatrixPowerBase -{ - public: - enum { - RowsAtCompileTime = MatrixType::RowsAtCompileTime, - ColsAtCompileTime = MatrixType::ColsAtCompileTime, - Options = MatrixType::Options, - MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime - }; - typedef typename MatrixType::Scalar Scalar; - typedef typename MatrixType::RealScalar RealScalar; - typedef typename MatrixType::Index Index; - - explicit MatrixPowerBase(const MatrixType& A, RealScalar cond); - - void compute(MatrixType& res, RealScalar p); - - template - void compute(const OtherDerived& b, ResultType& res, RealScalar p); - - Index rows() const { return m_A.rows(); } - Index cols() const { return m_A.cols(); } - - protected: - typedef Array RealArray; - - const MatrixType& m_A; - const MatrixType m_Id; - MatrixType m_tmp1, m_tmp2; - RealScalar m_conditionNumber; -}; - -template -MatrixPowerBase::MatrixPowerBase(const MatrixType& A, RealScalar cond) : - m_A(A), - m_Id(MatrixType::Identity(A.rows(),A.cols())), - m_conditionNumber(cond) -{ eigen_assert(A.rows() == A.cols()); } - -template -void MatrixPowerBase::compute(MatrixType& res, RealScalar p) -{ static_cast(this)->compute(res,p); } - -template -template -void MatrixPowerBase::compute(const OtherDerived& b, ResultType& res, RealScalar p) -{ static_cast(this)->compute(b,res,p); } - -template -class MatrixPowerProductBase : public MatrixBase -{ - public: - typedef MatrixBase Base; - EIGEN_DENSE_PUBLIC_INTERFACE(MatrixPowerProductBase) - - inline Index rows() const { return derived().rows(); } - inline Index cols() const { return derived().cols(); } - - template - inline void evalTo(ResultType& res) const { derived().evalTo(res); } -}; - -template -template -Derived& MatrixBase::lazyAssign(const MatrixPowerProductBase& other) -{ - other.derived().evalTo(derived()); - return derived(); -} - } // namespace Eigen #endif // EIGEN_MATRIX_POWER