// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2012, 2013 Chen-Pang He <jdh8@ms63.hinet.net> // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
/** * \ingroup MatrixFunctions_Module * * \brief Proxy for the matrix power of some matrix. * * \tparam MatrixType type of the base, a matrix. * * This class holds the arguments to the matrix power until it is * assigned or evaluated for some other reason (so the argument * should not be changed in the meantime). It is the return type of * MatrixPower::operator() and related functions and most of the * time this is the only way it is used.
*/ /* TODO This class is only used by MatrixPower, so it should be nested * into MatrixPower, like MatrixPower::ReturnValue. However, my * compiler complained about unused template parameter in the * following declaration in namespace internal. * * template<typename MatrixType> * struct traits<MatrixPower<MatrixType>::ReturnValue>;
*/ template<typename MatrixType> class MatrixPowerParenthesesReturnValue : public ReturnByValue< MatrixPowerParenthesesReturnValue<MatrixType> >
{ public: typedeftypename MatrixType::RealScalar RealScalar;
/** * \brief Constructor. * * \param[in] pow %MatrixPower storing the base. * \param[in] p scalar, the exponent of the matrix power.
*/
MatrixPowerParenthesesReturnValue(MatrixPower<MatrixType>& pow, RealScalar p) : m_pow(pow), m_p(p)
{ }
/** * \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 triangular real/complex matrices * raised to a power in the interval \f$ (-1, 1) \f$. * * \note Currently this class is only used by MatrixPower. One may * insist that this be nested into MatrixPower. This class is here to * facilitate future development of triangular matrix functions.
*/ template<typename MatrixType> class MatrixPowerAtomic : internal::noncopyable
{ private: enum {
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime
}; typedeftypename MatrixType::Scalar Scalar; typedeftypename MatrixType::RealScalar RealScalar; typedef std::complex<RealScalar> ComplexScalar; typedef Block<MatrixType,Dynamic,Dynamic> ResultType;
public: /** * \brief Constructor. * * \param[in] T the base of the matrix power. * \param[in] p the exponent of the matrix power, should be in * \f$ (-1, 1) \f$. * * The class stores a reference to T, so it should not be changed * (or destroyed) before evaluation. Only the upper triangular * part of T is read.
*/
MatrixPowerAtomic(const MatrixType& T, RealScalar p);
/** * \brief Compute the matrix power. * * \param[out] res \f$ A^p \f$ where A and p are specified in the * constructor.
*/ void compute(ResultType& res) const;
};
template<typename MatrixType> void MatrixPowerAtomic<MatrixType>::compute(ResultType& res) const
{ using std::pow; switch (m_A.rows()) { case 0: break; case 1:
res(0,0) = pow(m_A(0,0), m_p); break; case 2:
compute2x2(res, m_p); break; default:
computeBig(res);
}
}
template<typename MatrixType> void MatrixPowerAtomic<MatrixType>::computePade(int degree, const MatrixType& IminusT, ResultType& res) const
{ int i = 2*degree;
res = (m_p-RealScalar(degree)) / RealScalar(2*i-2) * IminusT;
for (--i; i; --i) {
res = (MatrixType::Identity(IminusT.rows(), IminusT.cols()) + res).template triangularView<Upper>()
.solve((i==1 ? -m_p : i&1 ? (-m_p-RealScalar(i/2))/RealScalar(2*i) : (m_p-RealScalar(i/2))/RealScalar(2*i-2)) * IminusT).eval();
}
res += MatrixType::Identity(IminusT.rows(), IminusT.cols());
}
// This function assumes that res has the correct size (see bug 614) template<typename MatrixType> void MatrixPowerAtomic<MatrixType>::compute2x2(ResultType& res, RealScalar p) const
{ using std::abs; using std::pow;
res.coeffRef(0,0) = pow(m_A.coeff(0,0), p);
/** * \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 real/complex matrices raised to * an arbitrary real power. Meanwhile, it saves the result of Schur * decomposition if an non-integral power has even been calculated. * Therefore, if you want to compute multiple (>= 2) matrix powers * for the same matrix, using the class directly is more efficient than * calling MatrixBase::pow(). * * Example: * \include MatrixPower_optimal.cpp * Output: \verbinclude MatrixPower_optimal.out
*/ template<typename MatrixType> class MatrixPower : internal::noncopyable
{ private: typedeftypename MatrixType::Scalar Scalar; typedeftypename MatrixType::RealScalar RealScalar;
public: /** * \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 MatrixPower(const MatrixType& A) :
m_A(A),
m_conditionNumber(0),
m_rank(A.cols()),
m_nulls(0)
{ eigen_assert(A.rows() == A.cols()); }
/** * \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 MatrixPowerParenthesesReturnValue<MatrixType> operator()(RealScalar p)
{ return MatrixPowerParenthesesReturnValue<MatrixType>(*this, p); }
/** * \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.
*/ template<typename ResultType> void compute(ResultType& res, RealScalar p);
Index rows() const { return m_A.rows(); }
Index cols() const { return m_A.cols(); }
/** \brief Store the result of Schur decomposition. */
ComplexMatrix m_T, m_U;
/** \brief Store fractional power of m_T. */
ComplexMatrix m_fT;
/** * \brief Condition number of m_A. * * It is initialized as 0 to avoid performing unnecessary Schur * decomposition, which is the bottleneck.
*/
RealScalar m_conditionNumber;
/** \brief Rank of m_A. */
Index m_rank;
/** \brief Rank deficiency of m_A. */
Index m_nulls;
/** * \brief Split p into integral part and fractional part. * * \param[in] p The exponent. * \param[out] p The fractional part ranging in \f$ (-1, 1) \f$. * \param[out] intpart The integral part. * * Only if the fractional part is nonzero, it calls initialize().
*/ void split(RealScalar& p, RealScalar& intpart);
template<int Rows, int Cols, int Options, int MaxRows, int MaxCols> staticvoid revertSchur(
Matrix<ComplexScalar, Rows, Cols, Options, MaxRows, MaxCols>& res, const ComplexMatrix& T, const ComplexMatrix& U);
template<int Rows, int Cols, int Options, int MaxRows, int MaxCols> staticvoid revertSchur(
Matrix<RealScalar, Rows, Cols, Options, MaxRows, MaxCols>& res, const ComplexMatrix& T, const ComplexMatrix& U);
};
template<typename MatrixType> template<typename ResultType> void MatrixPower<MatrixType>::compute(ResultType& res, RealScalar p)
{ using std::pow; switch (cols()) { case 0: break; case 1:
res(0,0) = pow(m_A.coeff(0,0), p); break; default:
RealScalar intpart;
split(p, intpart);
res = MatrixType::Identity(rows(), cols());
computeIntPower(res, intpart); if (p) computeFracPower(res, p);
}
}
template<typename MatrixType> void MatrixPower<MatrixType>::split(RealScalar& p, RealScalar& intpart)
{ using std::floor; using std::pow;
intpart = floor(p);
p -= intpart;
// Perform Schur decomposition if it is not yet performed and the power is // not an integer. if (!m_conditionNumber && p)
initialize();
// Choose the more stable of intpart = floor(p) and intpart = ceil(p). if (p > RealScalar(0.5) && p > (1-p) * pow(m_conditionNumber, p)) {
--p;
++intpart;
}
}
// Move zero eigenvalues to the bottom right corner. for (Index i = cols()-1; i>=0; --i) { if (m_rank <= 2) return; if (m_T.coeff(i,i) == RealScalar(0)) { for (Index j=i+1; j < m_rank; ++j) {
eigenvalue = m_T.coeff(j,j);
rot.makeGivens(m_T.coeff(j-1,j), eigenvalue);
m_T.applyOnTheRight(j-1, j, rot);
m_T.applyOnTheLeft(j-1, j, rot.adjoint());
m_T.coeffRef(j-1,j-1) = eigenvalue;
m_T.coeffRef(j,j) = RealScalar(0);
m_U.applyOnTheRight(j-1, j, rot);
}
--m_rank;
}
}
m_nulls = rows() - m_rank; if (m_nulls) {
eigen_assert(m_T.bottomRightCorner(m_nulls, m_nulls).isZero()
&& "Base of matrix power should be invertible or with a semisimple zero eigenvalue.");
m_fT.bottomRows(m_nulls).fill(RealScalar(0));
}
}
template<typename MatrixType> template<typename ResultType> void MatrixPower<MatrixType>::computeIntPower(ResultType& res, RealScalar p)
{ using std::abs; using std::fmod;
RealScalar pp = abs(p);
if (p<0)
m_tmp = m_A.inverse(); else
m_tmp = m_A;
while (true) { if (fmod(pp, 2) >= 1)
res = m_tmp * res;
pp /= 2; if (pp < 1) break;
m_tmp *= m_tmp;
}
}
template<typename MatrixType> template<int Rows, int Cols, int Options, int MaxRows, int MaxCols> inlinevoid MatrixPower<MatrixType>::revertSchur(
Matrix<ComplexScalar, Rows, Cols, Options, MaxRows, MaxCols>& res, const ComplexMatrix& T, const ComplexMatrix& U)
{ res.noalias() = U * (T.template triangularView<Upper>() * U.adjoint()); }
template<typename MatrixType> template<int Rows, int Cols, int Options, int MaxRows, int MaxCols> inlinevoid MatrixPower<MatrixType>::revertSchur(
Matrix<RealScalar, Rows, Cols, Options, MaxRows, MaxCols>& res, const ComplexMatrix& T, const ComplexMatrix& U)
{ res.noalias() = (U * (T.template triangularView<Upper>() * U.adjoint())).real(); }
/** * \ingroup MatrixFunctions_Module * * \brief Proxy for the matrix power of some matrix (expression). * * \tparam Derived type of the base, a matrix (expression). * * This class holds the arguments to the matrix power until it is * assigned or evaluated for some other reason (so the argument * should not be changed in the meantime). It is the return type of * MatrixBase::pow() and related functions and most of the * time this is the only way it is used.
*/ template<typename Derived> class MatrixPowerReturnValue : public ReturnByValue< MatrixPowerReturnValue<Derived> >
{ public: typedeftypename Derived::PlainObject PlainObject; typedeftypename Derived::RealScalar RealScalar;
/** * \brief Constructor. * * \param[in] A %Matrix (expression), the base of the matrix power. * \param[in] p real scalar, the exponent of the matrix power.
*/
MatrixPowerReturnValue(const Derived& A, RealScalar p) : m_A(A), m_p(p)
{ }
/** * \brief Compute the matrix power. * * \param[out] result \f$ A^p \f$ where \p A and \p p are as in the * constructor.
*/ template<typename ResultType> inlinevoid evalTo(ResultType& result) const
{ MatrixPower<PlainObject>(m_A.eval()).compute(result, m_p); }
Index rows() const { return m_A.rows(); }
Index cols() const { return m_A.cols(); }
/** * \ingroup MatrixFunctions_Module * * \brief Proxy for the matrix power of some matrix (expression). * * \tparam Derived type of the base, a matrix (expression). * * This class holds the arguments to the matrix power until it is * assigned or evaluated for some other reason (so the argument * should not be changed in the meantime). It is the return type of * MatrixBase::pow() and related functions and most of the * time this is the only way it is used.
*/ template<typename Derived> class MatrixComplexPowerReturnValue : public ReturnByValue< MatrixComplexPowerReturnValue<Derived> >
{ public: typedeftypename Derived::PlainObject PlainObject; typedeftypename std::complex<typename Derived::RealScalar> ComplexScalar;
/** * \brief Constructor. * * \param[in] A %Matrix (expression), the base of the matrix power. * \param[in] p complex scalar, the exponent of the matrix power.
*/
MatrixComplexPowerReturnValue(const Derived& A, const ComplexScalar& p) : m_A(A), m_p(p)
{ }
/** * \brief Compute the matrix power. * * Because \p p is complex, \f$ A^p \f$ is simply evaluated as \f$ * \exp(p \log(A)) \f$. * * \param[out] result \f$ A^p \f$ where \p A and \p p are as in the * constructor.
*/ template<typename ResultType> inlinevoid evalTo(ResultType& result) const
{ result = (m_p * m_A.log()).exp(); }
Index rows() const { return m_A.rows(); }
Index cols() const { return m_A.cols(); }
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.