mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-08-12 19:59:05 +08:00
Merge in jdh8's branch.
* Enable singular matrix power and complex exponents. * Eliminate unnecessary copying for sparse Kronecker product.
This commit is contained in:
commit
5879937f58
@ -332,37 +332,45 @@ inline NewType cast(const OldType& x)
|
|||||||
* Implementation of atanh2 *
|
* Implementation of atanh2 *
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
template<typename Scalar, bool IsInteger>
|
template<typename Scalar>
|
||||||
struct atanh2_default_impl
|
struct atanh2_impl
|
||||||
{
|
{
|
||||||
typedef Scalar retval;
|
static inline Scalar run(const Scalar& x, const Scalar& r)
|
||||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
{
|
||||||
static inline Scalar run(const Scalar& x, const Scalar& y)
|
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar)
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
using std::log1p;
|
||||||
|
return log1p(2 * x / (r - x)) / 2;
|
||||||
|
#else
|
||||||
|
using std::abs;
|
||||||
|
using std::log;
|
||||||
|
using std::sqrt;
|
||||||
|
Scalar z = x / r;
|
||||||
|
if (r == 0 || abs(z) > sqrt(NumTraits<Scalar>::epsilon()))
|
||||||
|
return log((r + x) / (r - x)) / 2;
|
||||||
|
else
|
||||||
|
return z + z*z*z / 3;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename RealScalar>
|
||||||
|
struct atanh2_impl<std::complex<RealScalar> >
|
||||||
|
{
|
||||||
|
typedef std::complex<RealScalar> Scalar;
|
||||||
|
static inline Scalar run(const Scalar& x, const Scalar& r)
|
||||||
{
|
{
|
||||||
using std::abs;
|
|
||||||
using std::log;
|
using std::log;
|
||||||
|
using std::norm;
|
||||||
using std::sqrt;
|
using std::sqrt;
|
||||||
Scalar z = x / y;
|
Scalar z = x / r;
|
||||||
if (y == Scalar(0) || abs(z) > sqrt(NumTraits<RealScalar>::epsilon()))
|
if (r == Scalar(0) || norm(z) > NumTraits<RealScalar>::epsilon())
|
||||||
return RealScalar(0.5) * log((y + x) / (y - x));
|
return RealScalar(0.5) * log((r + x) / (r - x));
|
||||||
else
|
else
|
||||||
return z + z*z*z / RealScalar(3);
|
return z + z*z*z / RealScalar(3);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Scalar>
|
|
||||||
struct atanh2_default_impl<Scalar, true>
|
|
||||||
{
|
|
||||||
static inline Scalar run(const Scalar&, const Scalar&)
|
|
||||||
{
|
|
||||||
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar)
|
|
||||||
return Scalar(0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Scalar>
|
|
||||||
struct atanh2_impl : atanh2_default_impl<Scalar, NumTraits<Scalar>::IsInteger> {};
|
|
||||||
|
|
||||||
template<typename Scalar>
|
template<typename Scalar>
|
||||||
struct atanh2_retval
|
struct atanh2_retval
|
||||||
{
|
{
|
||||||
|
@ -162,9 +162,6 @@ template<typename Derived> class MatrixBase
|
|||||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||||
template<typename ProductDerived, typename Lhs, typename Rhs>
|
template<typename ProductDerived, typename Lhs, typename Rhs>
|
||||||
Derived& lazyAssign(const ProductBase<ProductDerived, Lhs,Rhs>& other);
|
Derived& lazyAssign(const ProductBase<ProductDerived, Lhs,Rhs>& other);
|
||||||
|
|
||||||
template<typename MatrixPower, typename Lhs, typename Rhs>
|
|
||||||
Derived& lazyAssign(const MatrixPowerProduct<MatrixPower, Lhs,Rhs>& other);
|
|
||||||
#endif // not EIGEN_PARSED_BY_DOXYGEN
|
#endif // not EIGEN_PARSED_BY_DOXYGEN
|
||||||
|
|
||||||
template<typename OtherDerived>
|
template<typename OtherDerived>
|
||||||
@ -458,6 +455,7 @@ template<typename Derived> class MatrixBase
|
|||||||
const MatrixSquareRootReturnValue<Derived> sqrt() const;
|
const MatrixSquareRootReturnValue<Derived> sqrt() const;
|
||||||
const MatrixLogarithmReturnValue<Derived> log() const;
|
const MatrixLogarithmReturnValue<Derived> log() const;
|
||||||
const MatrixPowerReturnValue<Derived> pow(const RealScalar& p) const;
|
const MatrixPowerReturnValue<Derived> pow(const RealScalar& p) const;
|
||||||
|
const MatrixComplexPowerReturnValue<Derived> pow(const std::complex<RealScalar>& p) const;
|
||||||
|
|
||||||
#ifdef EIGEN2_SUPPORT
|
#ifdef EIGEN2_SUPPORT
|
||||||
template<typename ProductDerived, typename Lhs, typename Rhs>
|
template<typename ProductDerived, typename Lhs, typename Rhs>
|
||||||
|
@ -271,7 +271,7 @@ template<typename Derived> class MatrixFunctionReturnValue;
|
|||||||
template<typename Derived> class MatrixSquareRootReturnValue;
|
template<typename Derived> class MatrixSquareRootReturnValue;
|
||||||
template<typename Derived> class MatrixLogarithmReturnValue;
|
template<typename Derived> class MatrixLogarithmReturnValue;
|
||||||
template<typename Derived> class MatrixPowerReturnValue;
|
template<typename Derived> class MatrixPowerReturnValue;
|
||||||
template<typename Derived, typename Lhs, typename Rhs> class MatrixPowerProduct;
|
template<typename Derived> class MatrixComplexPowerReturnValue;
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
template <typename Scalar>
|
template <typename Scalar>
|
||||||
|
@ -13,8 +13,6 @@
|
|||||||
|
|
||||||
#include <cfloat>
|
#include <cfloat>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <functional>
|
|
||||||
#include <iterator>
|
|
||||||
|
|
||||||
#include <Eigen/Core>
|
#include <Eigen/Core>
|
||||||
#include <Eigen/LU>
|
#include <Eigen/LU>
|
||||||
@ -230,22 +228,65 @@ const MatrixPowerReturnValue<Derived> MatrixBase<Derived>::pow(RealScalar p) 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 real.
|
\param[in] p exponent of the matrix power.
|
||||||
|
|
||||||
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
|
If \p p is complex, the scalar type of \p M should be the type of \p
|
||||||
matrix logarithm. If \p p is not of the real scalar type of \p M, it
|
p . \f$ M^p \f$ simply evaluates into \f$ \exp(p \log(M)) \f$.
|
||||||
is casted into the real scalar type of \p M.
|
Therefore, the matrix \f$ M \f$ should meet the conditions to be an
|
||||||
|
argument of matrix logarithm.
|
||||||
|
|
||||||
This function computes the matrix power using the Schur-Padé
|
If \p p is real, it is casted into the real scalar type of \p M. Then
|
||||||
|
this function computes the matrix power using the Schur-Padé
|
||||||
algorithm as implemented by class MatrixPower. The exponent is split
|
algorithm as implemented by class MatrixPower. The exponent is split
|
||||||
into integral part and fractional part, where the fractional part is
|
into integral part and fractional part, where the fractional part is
|
||||||
in the interval \f$ (-1, 1) \f$. The main diagonal and the first
|
in the interval \f$ (-1, 1) \f$. The main diagonal and the first
|
||||||
super-diagonal is directly computed.
|
super-diagonal is directly computed.
|
||||||
|
|
||||||
|
If \p M is singular with a semisimple zero eigenvalue and \p p is
|
||||||
|
positive, the Schur factor \f$ T \f$ is reordered with Givens
|
||||||
|
rotations, i.e.
|
||||||
|
|
||||||
|
\f[ T = \left[ \begin{array}{cc}
|
||||||
|
T_1 & T_2 \\
|
||||||
|
0 & 0
|
||||||
|
\end{array} \right] \f]
|
||||||
|
|
||||||
|
where \f$ T_1 \f$ is invertible. Then \f$ T^p \f$ is given by
|
||||||
|
|
||||||
|
\f[ T^p = \left[ \begin{array}{cc}
|
||||||
|
T_1^p & T_1^{-1} T_1^p T_2 \\
|
||||||
|
0 & 0
|
||||||
|
\end{array}. \right] \f]
|
||||||
|
|
||||||
|
\warning Fractional power of a matrix with a non-semisimple zero
|
||||||
|
eigenvalue is not well-defined. We introduce an assertion failure
|
||||||
|
against inaccurate result, e.g. \code
|
||||||
|
#include <unsupported/Eigen/MatrixFunctions>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
Eigen::Matrix4d A;
|
||||||
|
A << 0, 0, 2, 3,
|
||||||
|
0, 0, 4, 5,
|
||||||
|
0, 0, 6, 7,
|
||||||
|
0, 0, 8, 9;
|
||||||
|
std::cout << A.pow(0.37) << std::endl;
|
||||||
|
|
||||||
|
// The 1 makes eigenvalue 0 non-semisimple.
|
||||||
|
A.coeffRef(0, 1) = 1;
|
||||||
|
|
||||||
|
// This fails if EIGEN_NO_DEBUG is undefined.
|
||||||
|
std::cout << A.pow(0.37) << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
|
||||||
Details of the algorithm can be found in: Nicholas J. Higham and
|
Details of the algorithm can be found in: Nicholas J. Higham and
|
||||||
Lijing Lin, "A Schur-Padé algorithm for fractional powers of a
|
Lijing Lin, "A Schur-Padé algorithm for fractional powers of a
|
||||||
matrix," <em>SIAM J. %Matrix Anal. Applic.</em>,
|
matrix," <em>SIAM J. %Matrix Anal. Applic.</em>,
|
||||||
|
@ -12,11 +12,64 @@
|
|||||||
#ifndef KRONECKER_TENSOR_PRODUCT_H
|
#ifndef KRONECKER_TENSOR_PRODUCT_H
|
||||||
#define KRONECKER_TENSOR_PRODUCT_H
|
#define KRONECKER_TENSOR_PRODUCT_H
|
||||||
|
|
||||||
namespace Eigen {
|
namespace Eigen {
|
||||||
|
|
||||||
template<typename Scalar, int Options, typename Index> class SparseMatrix;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
* \ingroup KroneckerProduct_Module
|
||||||
|
*
|
||||||
|
* \brief The base class of dense and sparse Kronecker product.
|
||||||
|
*
|
||||||
|
* \tparam Derived is the derived type.
|
||||||
|
*/
|
||||||
|
template<typename Derived>
|
||||||
|
class KroneckerProductBase : public ReturnByValue<Derived>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef typename internal::traits<Derived> Traits;
|
||||||
|
typedef typename Traits::Lhs Lhs;
|
||||||
|
typedef typename Traits::Rhs Rhs;
|
||||||
|
typedef typename Traits::Scalar Scalar;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
typedef typename Traits::Index Index;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*! \brief Constructor. */
|
||||||
|
KroneckerProductBase(const Lhs& A, const Rhs& B)
|
||||||
|
: m_A(A), m_B(B)
|
||||||
|
{}
|
||||||
|
|
||||||
|
inline Index rows() const { return m_A.rows() * m_B.rows(); }
|
||||||
|
inline Index cols() const { return m_A.cols() * m_B.cols(); }
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This overrides ReturnByValue::coeff because this function is
|
||||||
|
* efficient enough.
|
||||||
|
*/
|
||||||
|
Scalar coeff(Index row, Index col) const
|
||||||
|
{
|
||||||
|
return m_A.coeff(row / m_B.rows(), col / m_B.cols()) *
|
||||||
|
m_B.coeff(row % m_B.rows(), col % m_B.cols());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* This overrides ReturnByValue::coeff because this function is
|
||||||
|
* efficient enough.
|
||||||
|
*/
|
||||||
|
Scalar coeff(Index i) const
|
||||||
|
{
|
||||||
|
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived);
|
||||||
|
return m_A.coeff(i / m_A.size()) * m_B.coeff(i % m_A.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
typename Lhs::Nested m_A;
|
||||||
|
typename Rhs::Nested m_B;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \ingroup KroneckerProduct_Module
|
||||||
|
*
|
||||||
* \brief Kronecker tensor product helper class for dense matrices
|
* \brief Kronecker tensor product helper class for dense matrices
|
||||||
*
|
*
|
||||||
* This class is the return value of kroneckerProduct(MatrixBase,
|
* This class is the return value of kroneckerProduct(MatrixBase,
|
||||||
@ -27,43 +80,26 @@ template<typename Scalar, int Options, typename Index> class SparseMatrix;
|
|||||||
* \tparam Rhs Type of the rignt-hand side, a matrix expression.
|
* \tparam Rhs Type of the rignt-hand side, a matrix expression.
|
||||||
*/
|
*/
|
||||||
template<typename Lhs, typename Rhs>
|
template<typename Lhs, typename Rhs>
|
||||||
class KroneckerProduct : public ReturnByValue<KroneckerProduct<Lhs,Rhs> >
|
class KroneckerProduct : public KroneckerProductBase<KroneckerProduct<Lhs,Rhs> >
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
typedef ReturnByValue<KroneckerProduct> Base;
|
typedef KroneckerProductBase<KroneckerProduct> Base;
|
||||||
typedef typename Base::Scalar Scalar;
|
using Base::m_A;
|
||||||
typedef typename Base::Index Index;
|
using Base::m_B;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*! \brief Constructor. */
|
/*! \brief Constructor. */
|
||||||
KroneckerProduct(const Lhs& A, const Rhs& B)
|
KroneckerProduct(const Lhs& A, const Rhs& B)
|
||||||
: m_A(A), m_B(B)
|
: Base(A, B)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/*! \brief Evaluate the Kronecker tensor product. */
|
/*! \brief Evaluate the Kronecker tensor product. */
|
||||||
template<typename Dest> void evalTo(Dest& dst) const;
|
template<typename Dest> void evalTo(Dest& dst) const;
|
||||||
|
|
||||||
inline Index rows() const { return m_A.rows() * m_B.rows(); }
|
|
||||||
inline Index cols() const { return m_A.cols() * m_B.cols(); }
|
|
||||||
|
|
||||||
Scalar coeff(Index row, Index col) const
|
|
||||||
{
|
|
||||||
return m_A.coeff(row / m_B.rows(), col / m_B.cols()) *
|
|
||||||
m_B.coeff(row % m_B.rows(), col % m_B.cols());
|
|
||||||
}
|
|
||||||
|
|
||||||
Scalar coeff(Index i) const
|
|
||||||
{
|
|
||||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(KroneckerProduct);
|
|
||||||
return m_A.coeff(i / m_A.size()) * m_B.coeff(i % m_A.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
typename Lhs::Nested m_A;
|
|
||||||
typename Rhs::Nested m_B;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
* \ingroup KroneckerProduct_Module
|
||||||
|
*
|
||||||
* \brief Kronecker tensor product helper class for sparse matrices
|
* \brief Kronecker tensor product helper class for sparse matrices
|
||||||
*
|
*
|
||||||
* If at least one of the operands is a sparse matrix expression,
|
* If at least one of the operands is a sparse matrix expression,
|
||||||
@ -77,40 +113,28 @@ class KroneckerProduct : public ReturnByValue<KroneckerProduct<Lhs,Rhs> >
|
|||||||
* \tparam Rhs Type of the rignt-hand side, a matrix expression.
|
* \tparam Rhs Type of the rignt-hand side, a matrix expression.
|
||||||
*/
|
*/
|
||||||
template<typename Lhs, typename Rhs>
|
template<typename Lhs, typename Rhs>
|
||||||
class KroneckerProductSparse : public EigenBase<KroneckerProductSparse<Lhs,Rhs> >
|
class KroneckerProductSparse : public KroneckerProductBase<KroneckerProductSparse<Lhs,Rhs> >
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
typedef typename internal::traits<KroneckerProductSparse>::Index Index;
|
typedef KroneckerProductBase<KroneckerProductSparse> Base;
|
||||||
|
using Base::m_A;
|
||||||
|
using Base::m_B;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*! \brief Constructor. */
|
/*! \brief Constructor. */
|
||||||
KroneckerProductSparse(const Lhs& A, const Rhs& B)
|
KroneckerProductSparse(const Lhs& A, const Rhs& B)
|
||||||
: m_A(A), m_B(B)
|
: Base(A, B)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/*! \brief Evaluate the Kronecker tensor product. */
|
/*! \brief Evaluate the Kronecker tensor product. */
|
||||||
template<typename Dest> void evalTo(Dest& dst) const;
|
template<typename Dest> void evalTo(Dest& dst) const;
|
||||||
|
|
||||||
inline Index rows() const { return m_A.rows() * m_B.rows(); }
|
|
||||||
inline Index cols() const { return m_A.cols() * m_B.cols(); }
|
|
||||||
|
|
||||||
template<typename Scalar, int Options, typename Index>
|
|
||||||
operator SparseMatrix<Scalar, Options, Index>()
|
|
||||||
{
|
|
||||||
SparseMatrix<Scalar, Options, Index> result;
|
|
||||||
evalTo(result.derived());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
typename Lhs::Nested m_A;
|
|
||||||
typename Rhs::Nested m_B;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Lhs, typename Rhs>
|
template<typename Lhs, typename Rhs>
|
||||||
template<typename Dest>
|
template<typename Dest>
|
||||||
void KroneckerProduct<Lhs,Rhs>::evalTo(Dest& dst) const
|
void KroneckerProduct<Lhs,Rhs>::evalTo(Dest& dst) const
|
||||||
{
|
{
|
||||||
|
typedef typename Base::Index Index;
|
||||||
const int BlockRows = Rhs::RowsAtCompileTime,
|
const int BlockRows = Rhs::RowsAtCompileTime,
|
||||||
BlockCols = Rhs::ColsAtCompileTime;
|
BlockCols = Rhs::ColsAtCompileTime;
|
||||||
const Index Br = m_B.rows(),
|
const Index Br = m_B.rows(),
|
||||||
@ -124,9 +148,10 @@ template<typename Lhs, typename Rhs>
|
|||||||
template<typename Dest>
|
template<typename Dest>
|
||||||
void KroneckerProductSparse<Lhs,Rhs>::evalTo(Dest& dst) const
|
void KroneckerProductSparse<Lhs,Rhs>::evalTo(Dest& dst) const
|
||||||
{
|
{
|
||||||
|
typedef typename Base::Index Index;
|
||||||
const Index Br = m_B.rows(),
|
const Index Br = m_B.rows(),
|
||||||
Bc = m_B.cols();
|
Bc = m_B.cols();
|
||||||
dst.resize(rows(),cols());
|
dst.resize(this->rows(), this->cols());
|
||||||
dst.resizeNonZeros(0);
|
dst.resizeNonZeros(0);
|
||||||
dst.reserve(m_A.nonZeros() * m_B.nonZeros());
|
dst.reserve(m_A.nonZeros() * m_B.nonZeros());
|
||||||
|
|
||||||
@ -155,6 +180,7 @@ struct traits<KroneckerProduct<_Lhs,_Rhs> >
|
|||||||
typedef typename remove_all<_Lhs>::type Lhs;
|
typedef typename remove_all<_Lhs>::type Lhs;
|
||||||
typedef typename remove_all<_Rhs>::type Rhs;
|
typedef typename remove_all<_Rhs>::type Rhs;
|
||||||
typedef typename scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType Scalar;
|
typedef typename scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType Scalar;
|
||||||
|
typedef typename promote_index_type<typename Lhs::Index, typename Rhs::Index>::type Index;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
Rows = size_at_compile_time<traits<Lhs>::RowsAtCompileTime, traits<Rhs>::RowsAtCompileTime>::ret,
|
Rows = size_at_compile_time<traits<Lhs>::RowsAtCompileTime, traits<Rhs>::RowsAtCompileTime>::ret,
|
||||||
@ -193,6 +219,8 @@ struct traits<KroneckerProductSparse<_Lhs,_Rhs> >
|
|||||||
| EvalBeforeNestingBit | EvalBeforeAssigningBit,
|
| EvalBeforeNestingBit | EvalBeforeAssigningBit,
|
||||||
CoeffReadCost = Dynamic
|
CoeffReadCost = Dynamic
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef SparseMatrix<Scalar> ReturnType;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace internal
|
} // end namespace internal
|
||||||
@ -228,6 +256,16 @@ KroneckerProduct<A,B> kroneckerProduct(const MatrixBase<A>& a, const MatrixBase<
|
|||||||
* Computes Kronecker tensor product of two matrices, at least one of
|
* Computes Kronecker tensor product of two matrices, at least one of
|
||||||
* which is sparse
|
* which is sparse
|
||||||
*
|
*
|
||||||
|
* \warning If you want to replace a matrix by its Kronecker product
|
||||||
|
* with some matrix, do \b NOT do this:
|
||||||
|
* \code
|
||||||
|
* A = kroneckerProduct(A,B); // bug!!! caused by aliasing effect
|
||||||
|
* \endcode
|
||||||
|
* instead, use eval() to work around this:
|
||||||
|
* \code
|
||||||
|
* A = kroneckerProduct(A,B).eval();
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
* \param a Dense/sparse matrix a
|
* \param a Dense/sparse matrix a
|
||||||
* \param b Dense/sparse matrix b
|
* \param b Dense/sparse matrix b
|
||||||
* \return Kronecker tensor product of a and b, stored in a sparse
|
* \return Kronecker tensor product of a and b, stored in a sparse
|
||||||
|
@ -21,8 +21,8 @@ namespace Eigen {
|
|||||||
* expected to be an instantiation of the Matrix class template.
|
* expected to be an instantiation of the Matrix class template.
|
||||||
*/
|
*/
|
||||||
template <typename MatrixType>
|
template <typename MatrixType>
|
||||||
class MatrixExponential {
|
class MatrixExponential : internal::noncopyable
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** \brief Constructor.
|
/** \brief Constructor.
|
||||||
@ -32,7 +32,7 @@ class MatrixExponential {
|
|||||||
*
|
*
|
||||||
* \param[in] M matrix whose exponential is to be computed.
|
* \param[in] M matrix whose exponential is to be computed.
|
||||||
*/
|
*/
|
||||||
MatrixExponential(const MatrixType &M);
|
explicit MatrixExponential(const MatrixType &M);
|
||||||
|
|
||||||
/** \brief Computes the matrix exponential.
|
/** \brief Computes the matrix exponential.
|
||||||
*
|
*
|
||||||
@ -43,10 +43,6 @@ class MatrixExponential {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Prevent copying
|
|
||||||
MatrixExponential(const MatrixExponential&);
|
|
||||||
MatrixExponential& operator=(const MatrixExponential&);
|
|
||||||
|
|
||||||
/** \brief Compute the (3,3)-Padé approximant to the exponential.
|
/** \brief Compute the (3,3)-Padé approximant to the exponential.
|
||||||
*
|
*
|
||||||
* After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Padé
|
* After exit, \f$ (V+U)(V-U)^{-1} \f$ is the Padé
|
||||||
@ -130,6 +126,7 @@ class MatrixExponential {
|
|||||||
*/
|
*/
|
||||||
void computeUV(long double);
|
void computeUV(long double);
|
||||||
|
|
||||||
|
struct ScalingOp;
|
||||||
typedef typename internal::traits<MatrixType>::Scalar Scalar;
|
typedef typename internal::traits<MatrixType>::Scalar Scalar;
|
||||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||||
typedef typename std::complex<RealScalar> ComplexScalar;
|
typedef typename std::complex<RealScalar> ComplexScalar;
|
||||||
@ -159,6 +156,43 @@ class MatrixExponential {
|
|||||||
RealScalar m_l1norm;
|
RealScalar m_l1norm;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** \brief Scaling operator.
|
||||||
|
*
|
||||||
|
* This struct is used by CwiseUnaryOp to scale a matrix by \f$ 2^{-s} \f$.
|
||||||
|
*/
|
||||||
|
template <typename MatrixType>
|
||||||
|
struct MatrixExponential<MatrixType>::ScalingOp
|
||||||
|
{
|
||||||
|
/** \brief Constructor.
|
||||||
|
*
|
||||||
|
* \param[in] squarings The integer \f$ s \f$ in this document.
|
||||||
|
*/
|
||||||
|
ScalingOp(int squarings) : m_squarings(squarings) { }
|
||||||
|
|
||||||
|
/** \brief Scale a matrix coefficient.
|
||||||
|
*
|
||||||
|
* \param[in,out] x The scalar to be scaled, becoming \f$ 2^{-s} x \f$.
|
||||||
|
*/
|
||||||
|
inline const RealScalar operator() (const RealScalar& x) const
|
||||||
|
{
|
||||||
|
using std::ldexp;
|
||||||
|
return ldexp(x, -m_squarings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Scale a matrix coefficient.
|
||||||
|
*
|
||||||
|
* \param[in,out] x The scalar to be scaled, becoming \f$ 2^{-s} x \f$.
|
||||||
|
*/
|
||||||
|
inline const ComplexScalar operator() (const ComplexScalar& x) const
|
||||||
|
{
|
||||||
|
using std::ldexp;
|
||||||
|
return ComplexScalar(ldexp(x.real(), -m_squarings), ldexp(x.imag(), -m_squarings));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_squarings;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename MatrixType>
|
template <typename MatrixType>
|
||||||
MatrixExponential<MatrixType>::MatrixExponential(const MatrixType &M) :
|
MatrixExponential<MatrixType>::MatrixExponential(const MatrixType &M) :
|
||||||
m_M(M),
|
m_M(M),
|
||||||
@ -284,7 +318,6 @@ template <typename MatrixType>
|
|||||||
void MatrixExponential<MatrixType>::computeUV(float)
|
void MatrixExponential<MatrixType>::computeUV(float)
|
||||||
{
|
{
|
||||||
using std::frexp;
|
using std::frexp;
|
||||||
using std::pow;
|
|
||||||
if (m_l1norm < 4.258730016922831e-001) {
|
if (m_l1norm < 4.258730016922831e-001) {
|
||||||
pade3(m_M);
|
pade3(m_M);
|
||||||
} else if (m_l1norm < 1.880152677804762e+000) {
|
} else if (m_l1norm < 1.880152677804762e+000) {
|
||||||
@ -293,7 +326,7 @@ void MatrixExponential<MatrixType>::computeUV(float)
|
|||||||
const float maxnorm = 3.925724783138660f;
|
const float maxnorm = 3.925724783138660f;
|
||||||
frexp(m_l1norm / maxnorm, &m_squarings);
|
frexp(m_l1norm / maxnorm, &m_squarings);
|
||||||
if (m_squarings < 0) m_squarings = 0;
|
if (m_squarings < 0) m_squarings = 0;
|
||||||
MatrixType A = m_M / pow(Scalar(2), m_squarings);
|
MatrixType A = CwiseUnaryOp<ScalingOp, const MatrixType>(m_M, m_squarings);
|
||||||
pade7(A);
|
pade7(A);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,7 +335,6 @@ template <typename MatrixType>
|
|||||||
void MatrixExponential<MatrixType>::computeUV(double)
|
void MatrixExponential<MatrixType>::computeUV(double)
|
||||||
{
|
{
|
||||||
using std::frexp;
|
using std::frexp;
|
||||||
using std::pow;
|
|
||||||
if (m_l1norm < 1.495585217958292e-002) {
|
if (m_l1norm < 1.495585217958292e-002) {
|
||||||
pade3(m_M);
|
pade3(m_M);
|
||||||
} else if (m_l1norm < 2.539398330063230e-001) {
|
} else if (m_l1norm < 2.539398330063230e-001) {
|
||||||
@ -315,7 +347,7 @@ void MatrixExponential<MatrixType>::computeUV(double)
|
|||||||
const double maxnorm = 5.371920351148152;
|
const double maxnorm = 5.371920351148152;
|
||||||
frexp(m_l1norm / maxnorm, &m_squarings);
|
frexp(m_l1norm / maxnorm, &m_squarings);
|
||||||
if (m_squarings < 0) m_squarings = 0;
|
if (m_squarings < 0) m_squarings = 0;
|
||||||
MatrixType A = m_M / pow(Scalar(2), m_squarings);
|
MatrixType A = CwiseUnaryOp<ScalingOp, const MatrixType>(m_M, m_squarings);
|
||||||
pade13(A);
|
pade13(A);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -324,7 +356,6 @@ template <typename MatrixType>
|
|||||||
void MatrixExponential<MatrixType>::computeUV(long double)
|
void MatrixExponential<MatrixType>::computeUV(long double)
|
||||||
{
|
{
|
||||||
using std::frexp;
|
using std::frexp;
|
||||||
using std::pow;
|
|
||||||
#if LDBL_MANT_DIG == 53 // double precision
|
#if LDBL_MANT_DIG == 53 // double precision
|
||||||
computeUV(double());
|
computeUV(double());
|
||||||
#elif LDBL_MANT_DIG <= 64 // extended precision
|
#elif LDBL_MANT_DIG <= 64 // extended precision
|
||||||
@ -340,7 +371,7 @@ void MatrixExponential<MatrixType>::computeUV(long double)
|
|||||||
const long double maxnorm = 4.0246098906697353063L;
|
const long double maxnorm = 4.0246098906697353063L;
|
||||||
frexp(m_l1norm / maxnorm, &m_squarings);
|
frexp(m_l1norm / maxnorm, &m_squarings);
|
||||||
if (m_squarings < 0) m_squarings = 0;
|
if (m_squarings < 0) m_squarings = 0;
|
||||||
MatrixType A = m_M / pow(Scalar(2), m_squarings);
|
MatrixType A = CwiseUnaryOp<ScalingOp, const MatrixType>(m_M, m_squarings);
|
||||||
pade13(A);
|
pade13(A);
|
||||||
}
|
}
|
||||||
#elif LDBL_MANT_DIG <= 106 // double-double
|
#elif LDBL_MANT_DIG <= 106 // double-double
|
||||||
@ -358,7 +389,7 @@ void MatrixExponential<MatrixType>::computeUV(long double)
|
|||||||
const long double maxnorm = 3.2579440895405400856599663723517L;
|
const long double maxnorm = 3.2579440895405400856599663723517L;
|
||||||
frexp(m_l1norm / maxnorm, &m_squarings);
|
frexp(m_l1norm / maxnorm, &m_squarings);
|
||||||
if (m_squarings < 0) m_squarings = 0;
|
if (m_squarings < 0) m_squarings = 0;
|
||||||
MatrixType A = m_M / pow(Scalar(2), m_squarings);
|
MatrixType A = CwiseUnaryOp<ScalingOp, const MatrixType>(m_M, m_squarings);
|
||||||
pade17(A);
|
pade17(A);
|
||||||
}
|
}
|
||||||
#elif LDBL_MANT_DIG <= 112 // quadruple precison
|
#elif LDBL_MANT_DIG <= 112 // quadruple precison
|
||||||
@ -376,7 +407,7 @@ void MatrixExponential<MatrixType>::computeUV(long double)
|
|||||||
const long double maxnorm = 2.884233277829519311757165057717815L;
|
const long double maxnorm = 2.884233277829519311757165057717815L;
|
||||||
frexp(m_l1norm / maxnorm, &m_squarings);
|
frexp(m_l1norm / maxnorm, &m_squarings);
|
||||||
if (m_squarings < 0) m_squarings = 0;
|
if (m_squarings < 0) m_squarings = 0;
|
||||||
MatrixType A = m_M / pow(Scalar(2), m_squarings);
|
MatrixType A = CwiseUnaryOp<ScalingOp, const MatrixType>(m_M, m_squarings);
|
||||||
pade17(A);
|
pade17(A);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -407,7 +438,7 @@ template<typename Derived> struct MatrixExponentialReturnValue
|
|||||||
* \param[in] src %Matrix (expression) forming the argument of the
|
* \param[in] src %Matrix (expression) forming the argument of the
|
||||||
* matrix exponential.
|
* matrix exponential.
|
||||||
*/
|
*/
|
||||||
MatrixExponentialReturnValue(const Derived& src) : m_src(src) { }
|
explicit MatrixExponentialReturnValue(const Derived& src) : m_src(src) { }
|
||||||
|
|
||||||
/** \brief Compute the matrix exponential.
|
/** \brief Compute the matrix exponential.
|
||||||
*
|
*
|
||||||
@ -427,8 +458,6 @@ template<typename Derived> struct MatrixExponentialReturnValue
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
const Derived& m_src;
|
const Derived& m_src;
|
||||||
private:
|
|
||||||
MatrixExponentialReturnValue& operator=(const MatrixExponentialReturnValue&);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -34,7 +34,7 @@ namespace Eigen {
|
|||||||
template <typename MatrixType,
|
template <typename MatrixType,
|
||||||
typename AtomicType,
|
typename AtomicType,
|
||||||
int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex>
|
int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex>
|
||||||
class MatrixFunction
|
class MatrixFunction : internal::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ class MatrixFunction
|
|||||||
* \brief Partial specialization of MatrixFunction for real matrices
|
* \brief Partial specialization of MatrixFunction for real matrices
|
||||||
*/
|
*/
|
||||||
template <typename MatrixType, typename AtomicType>
|
template <typename MatrixType, typename AtomicType>
|
||||||
class MatrixFunction<MatrixType, AtomicType, 0>
|
class MatrixFunction<MatrixType, AtomicType, 0> : internal::noncopyable
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -111,8 +111,6 @@ class MatrixFunction<MatrixType, AtomicType, 0>
|
|||||||
private:
|
private:
|
||||||
typename internal::nested<MatrixType>::type m_A; /**< \brief Reference to argument of matrix function. */
|
typename internal::nested<MatrixType>::type m_A; /**< \brief Reference to argument of matrix function. */
|
||||||
AtomicType& m_atomic; /**< \brief Class for computing matrix function of atomic blocks. */
|
AtomicType& m_atomic; /**< \brief Class for computing matrix function of atomic blocks. */
|
||||||
|
|
||||||
MatrixFunction& operator=(const MatrixFunction&);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -120,7 +118,7 @@ class MatrixFunction<MatrixType, AtomicType, 0>
|
|||||||
* \brief Partial specialization of MatrixFunction for complex matrices
|
* \brief Partial specialization of MatrixFunction for complex matrices
|
||||||
*/
|
*/
|
||||||
template <typename MatrixType, typename AtomicType>
|
template <typename MatrixType, typename AtomicType>
|
||||||
class MatrixFunction<MatrixType, AtomicType, 1>
|
class MatrixFunction<MatrixType, AtomicType, 1> : internal::noncopyable
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -176,8 +174,6 @@ class MatrixFunction<MatrixType, AtomicType, 1>
|
|||||||
* separation constant is set to 0.1, a value taken from the
|
* separation constant is set to 0.1, a value taken from the
|
||||||
* paper by Davies and Higham. */
|
* paper by Davies and Higham. */
|
||||||
static const RealScalar separation() { return static_cast<RealScalar>(0.1); }
|
static const RealScalar separation() { return static_cast<RealScalar>(0.1); }
|
||||||
|
|
||||||
MatrixFunction& operator=(const MatrixFunction&);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \brief Constructor.
|
/** \brief Constructor.
|
||||||
@ -531,8 +527,6 @@ template<typename Derived> class MatrixFunctionReturnValue
|
|||||||
private:
|
private:
|
||||||
typename internal::nested<Derived>::type m_A;
|
typename internal::nested<Derived>::type m_A;
|
||||||
StemFunction *m_f;
|
StemFunction *m_f;
|
||||||
|
|
||||||
MatrixFunctionReturnValue& operator=(const MatrixFunctionReturnValue&);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -21,7 +21,7 @@ namespace Eigen {
|
|||||||
* entries are close to each other.
|
* entries are close to each other.
|
||||||
*/
|
*/
|
||||||
template <typename MatrixType>
|
template <typename MatrixType>
|
||||||
class MatrixFunctionAtomic
|
class MatrixFunctionAtomic : internal::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -44,10 +44,6 @@ class MatrixFunctionAtomic
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Prevent copying
|
|
||||||
MatrixFunctionAtomic(const MatrixFunctionAtomic&);
|
|
||||||
MatrixFunctionAtomic& operator=(const MatrixFunctionAtomic&);
|
|
||||||
|
|
||||||
void computeMu();
|
void computeMu();
|
||||||
bool taylorConverged(Index s, const MatrixType& F, const MatrixType& Fincr, const MatrixType& P);
|
bool taylorConverged(Index s, const MatrixType& F, const MatrixType& Fincr, const MatrixType& P);
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ namespace Eigen {
|
|||||||
* \sa class MatrixFunctionAtomic, MatrixBase::log()
|
* \sa class MatrixFunctionAtomic, MatrixBase::log()
|
||||||
*/
|
*/
|
||||||
template <typename MatrixType>
|
template <typename MatrixType>
|
||||||
class MatrixLogarithmAtomic
|
class MatrixLogarithmAtomic : internal::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -71,10 +71,6 @@ private:
|
|||||||
std::numeric_limits<RealScalar>::digits<= 64? 8: // extended precision
|
std::numeric_limits<RealScalar>::digits<= 64? 8: // extended precision
|
||||||
std::numeric_limits<RealScalar>::digits<=106? 10: // double-double
|
std::numeric_limits<RealScalar>::digits<=106? 10: // double-double
|
||||||
11; // quadruple precision
|
11; // quadruple precision
|
||||||
|
|
||||||
// Prevent copying
|
|
||||||
MatrixLogarithmAtomic(const MatrixLogarithmAtomic&);
|
|
||||||
MatrixLogarithmAtomic& operator=(const MatrixLogarithmAtomic&);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \brief Compute logarithm of triangular matrix with clustered eigenvalues. */
|
/** \brief Compute logarithm of triangular matrix with clustered eigenvalues. */
|
||||||
@ -429,7 +425,7 @@ public:
|
|||||||
*
|
*
|
||||||
* \param[in] A %Matrix (expression) forming the argument of the matrix logarithm.
|
* \param[in] A %Matrix (expression) forming the argument of the matrix logarithm.
|
||||||
*/
|
*/
|
||||||
MatrixLogarithmReturnValue(const Derived& A) : m_A(A) { }
|
explicit MatrixLogarithmReturnValue(const Derived& A) : m_A(A) { }
|
||||||
|
|
||||||
/** \brief Compute the matrix logarithm.
|
/** \brief Compute the matrix logarithm.
|
||||||
*
|
*
|
||||||
@ -458,8 +454,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
typename internal::nested<Derived>::type m_A;
|
typename internal::nested<Derived>::type m_A;
|
||||||
|
|
||||||
MatrixLogarithmReturnValue& operator=(const MatrixLogarithmReturnValue&);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -14,16 +14,48 @@ namespace Eigen {
|
|||||||
|
|
||||||
template<typename MatrixType> class MatrixPower;
|
template<typename MatrixType> class MatrixPower;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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>
|
template<typename MatrixType>
|
||||||
class MatrixPowerRetval : public ReturnByValue< MatrixPowerRetval<MatrixType> >
|
class MatrixPowerParenthesesReturnValue : public ReturnByValue< MatrixPowerParenthesesReturnValue<MatrixType> >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef typename MatrixType::RealScalar RealScalar;
|
typedef typename MatrixType::RealScalar RealScalar;
|
||||||
typedef typename MatrixType::Index Index;
|
typedef typename MatrixType::Index Index;
|
||||||
|
|
||||||
MatrixPowerRetval(MatrixPower<MatrixType>& pow, RealScalar p) : m_pow(pow), m_p(p)
|
/**
|
||||||
|
* \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)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Compute the matrix power.
|
||||||
|
*
|
||||||
|
* \param[out] result
|
||||||
|
*/
|
||||||
template<typename ResultType>
|
template<typename ResultType>
|
||||||
inline void evalTo(ResultType& res) const
|
inline void evalTo(ResultType& res) const
|
||||||
{ m_pow.compute(res, m_p); }
|
{ m_pow.compute(res, m_p); }
|
||||||
@ -34,11 +66,25 @@ class MatrixPowerRetval : public ReturnByValue< MatrixPowerRetval<MatrixType> >
|
|||||||
private:
|
private:
|
||||||
MatrixPower<MatrixType>& m_pow;
|
MatrixPower<MatrixType>& m_pow;
|
||||||
const RealScalar m_p;
|
const RealScalar m_p;
|
||||||
MatrixPowerRetval& operator=(const MatrixPowerRetval&);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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
|
||||||
|
* faciliate future development of triangular matrix functions.
|
||||||
|
*/
|
||||||
template<typename MatrixType>
|
template<typename MatrixType>
|
||||||
class MatrixPowerAtomic
|
class MatrixPowerAtomic : internal::noncopyable
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
enum {
|
enum {
|
||||||
@ -49,14 +95,14 @@ class MatrixPowerAtomic
|
|||||||
typedef typename MatrixType::RealScalar RealScalar;
|
typedef typename MatrixType::RealScalar RealScalar;
|
||||||
typedef std::complex<RealScalar> ComplexScalar;
|
typedef std::complex<RealScalar> ComplexScalar;
|
||||||
typedef typename MatrixType::Index Index;
|
typedef typename MatrixType::Index Index;
|
||||||
typedef Array<Scalar, RowsAtCompileTime, 1, ColMajor, MaxRowsAtCompileTime> ArrayType;
|
typedef Block<MatrixType,Dynamic,Dynamic> ResultType;
|
||||||
|
|
||||||
const MatrixType& m_A;
|
const MatrixType& m_A;
|
||||||
RealScalar m_p;
|
RealScalar m_p;
|
||||||
|
|
||||||
void computePade(int degree, const MatrixType& IminusT, MatrixType& res) const;
|
void computePade(int degree, const MatrixType& IminusT, ResultType& res) const;
|
||||||
void compute2x2(MatrixType& res, RealScalar p) const;
|
void compute2x2(ResultType& res, RealScalar p) const;
|
||||||
void computeBig(MatrixType& res) const;
|
void computeBig(ResultType& res) const;
|
||||||
static int getPadeDegree(float normIminusT);
|
static int getPadeDegree(float normIminusT);
|
||||||
static int getPadeDegree(double normIminusT);
|
static int getPadeDegree(double normIminusT);
|
||||||
static int getPadeDegree(long double normIminusT);
|
static int getPadeDegree(long double normIminusT);
|
||||||
@ -64,24 +110,45 @@ class MatrixPowerAtomic
|
|||||||
static RealScalar computeSuperDiag(RealScalar, RealScalar, RealScalar p);
|
static RealScalar computeSuperDiag(RealScalar, RealScalar, RealScalar p);
|
||||||
|
|
||||||
public:
|
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);
|
MatrixPowerAtomic(const MatrixType& T, RealScalar p);
|
||||||
void compute(MatrixType& res) const;
|
|
||||||
|
/**
|
||||||
|
* \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>
|
template<typename MatrixType>
|
||||||
MatrixPowerAtomic<MatrixType>::MatrixPowerAtomic(const MatrixType& T, RealScalar p) :
|
MatrixPowerAtomic<MatrixType>::MatrixPowerAtomic(const MatrixType& T, RealScalar p) :
|
||||||
m_A(T), m_p(p)
|
m_A(T), m_p(p)
|
||||||
{ eigen_assert(T.rows() == T.cols()); }
|
{
|
||||||
|
eigen_assert(T.rows() == T.cols());
|
||||||
|
eigen_assert(p > -1 && p < 1);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename MatrixType>
|
template<typename MatrixType>
|
||||||
void MatrixPowerAtomic<MatrixType>::compute(MatrixType& res) const
|
void MatrixPowerAtomic<MatrixType>::compute(ResultType& res) const
|
||||||
{
|
{
|
||||||
res.resizeLike(m_A);
|
using std::pow;
|
||||||
switch (m_A.rows()) {
|
switch (m_A.rows()) {
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
res(0,0) = std::pow(m_A(0,0), m_p);
|
res(0,0) = pow(m_A(0,0), m_p);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
compute2x2(res, m_p);
|
compute2x2(res, m_p);
|
||||||
@ -92,25 +159,24 @@ void MatrixPowerAtomic<MatrixType>::compute(MatrixType& res) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename MatrixType>
|
template<typename MatrixType>
|
||||||
void MatrixPowerAtomic<MatrixType>::computePade(int degree, const MatrixType& IminusT, MatrixType& res) const
|
void MatrixPowerAtomic<MatrixType>::computePade(int degree, const MatrixType& IminusT, ResultType& res) const
|
||||||
{
|
{
|
||||||
int i = degree<<1;
|
int i = 2*degree;
|
||||||
res = (m_p-degree) / ((i-1)<<1) * IminusT;
|
res = (m_p-degree) / (2*i-2) * IminusT;
|
||||||
|
|
||||||
for (--i; i; --i) {
|
for (--i; i; --i) {
|
||||||
res = (MatrixType::Identity(IminusT.rows(), IminusT.cols()) + res).template triangularView<Upper>()
|
res = (MatrixType::Identity(IminusT.rows(), IminusT.cols()) + res).template triangularView<Upper>()
|
||||||
.solve((i==1 ? -m_p : i&1 ? (-m_p-(i>>1))/(i<<1) : (m_p-(i>>1))/((i-1)<<1)) * IminusT).eval();
|
.solve((i==1 ? -m_p : i&1 ? (-m_p-i/2)/(2*i) : (m_p-i/2)/(2*i-2)) * IminusT).eval();
|
||||||
}
|
}
|
||||||
res += MatrixType::Identity(IminusT.rows(), IminusT.cols());
|
res += MatrixType::Identity(IminusT.rows(), IminusT.cols());
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function assumes that res has the correct size (see bug 614)
|
// This function assumes that res has the correct size (see bug 614)
|
||||||
template<typename MatrixType>
|
template<typename MatrixType>
|
||||||
void MatrixPowerAtomic<MatrixType>::compute2x2(MatrixType& res, RealScalar p) const
|
void MatrixPowerAtomic<MatrixType>::compute2x2(ResultType& res, RealScalar p) const
|
||||||
{
|
{
|
||||||
using std::abs;
|
using std::abs;
|
||||||
using std::pow;
|
using std::pow;
|
||||||
|
|
||||||
ArrayType logTdiag = m_A.diagonal().array().log();
|
|
||||||
res.coeffRef(0,0) = pow(m_A.coeff(0,0), p);
|
res.coeffRef(0,0) = pow(m_A.coeff(0,0), p);
|
||||||
|
|
||||||
for (Index i=1; i < m_A.cols(); ++i) {
|
for (Index i=1; i < m_A.cols(); ++i) {
|
||||||
@ -126,8 +192,9 @@ void MatrixPowerAtomic<MatrixType>::compute2x2(MatrixType& res, RealScalar p) co
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename MatrixType>
|
template<typename MatrixType>
|
||||||
void MatrixPowerAtomic<MatrixType>::computeBig(MatrixType& res) const
|
void MatrixPowerAtomic<MatrixType>::computeBig(ResultType& res) const
|
||||||
{
|
{
|
||||||
|
using std::ldexp;
|
||||||
const int digits = std::numeric_limits<RealScalar>::digits;
|
const int digits = std::numeric_limits<RealScalar>::digits;
|
||||||
const RealScalar maxNormForPade = digits <= 24? 4.3386528e-1f: // sigle precision
|
const RealScalar maxNormForPade = digits <= 24? 4.3386528e-1f: // sigle precision
|
||||||
digits <= 53? 2.789358995219730e-1: // double precision
|
digits <= 53? 2.789358995219730e-1: // double precision
|
||||||
@ -139,19 +206,6 @@ void MatrixPowerAtomic<MatrixType>::computeBig(MatrixType& res) const
|
|||||||
int degree, degree2, numberOfSquareRoots = 0;
|
int degree, degree2, numberOfSquareRoots = 0;
|
||||||
bool hasExtraSquareRoot = false;
|
bool hasExtraSquareRoot = false;
|
||||||
|
|
||||||
/* FIXME
|
|
||||||
* For singular T, norm(I - T) >= 1 but maxNormForPade < 1, leads to infinite
|
|
||||||
* loop. We should move 0 eigenvalues to bottom right corner. We need not
|
|
||||||
* worry about tiny values (e.g. 1e-300) because they will reach 1 if
|
|
||||||
* repetitively sqrt'ed.
|
|
||||||
*
|
|
||||||
* If the 0 eigenvalues are semisimple, they can form a 0 matrix at the
|
|
||||||
* bottom right corner.
|
|
||||||
*
|
|
||||||
* [ T A ]^p [ T^p (T^-1 T^p A) ]
|
|
||||||
* [ ] = [ ]
|
|
||||||
* [ 0 0 ] [ 0 0 ]
|
|
||||||
*/
|
|
||||||
for (Index i=0; i < m_A.cols(); ++i)
|
for (Index i=0; i < m_A.cols(); ++i)
|
||||||
eigen_assert(m_A(i,i) != RealScalar(0));
|
eigen_assert(m_A(i,i) != RealScalar(0));
|
||||||
|
|
||||||
@ -172,7 +226,7 @@ void MatrixPowerAtomic<MatrixType>::computeBig(MatrixType& res) const
|
|||||||
computePade(degree, IminusT, res);
|
computePade(degree, IminusT, res);
|
||||||
|
|
||||||
for (; numberOfSquareRoots; --numberOfSquareRoots) {
|
for (; numberOfSquareRoots; --numberOfSquareRoots) {
|
||||||
compute2x2(res, std::ldexp(m_p, -numberOfSquareRoots));
|
compute2x2(res, ldexp(m_p, -numberOfSquareRoots));
|
||||||
res = res.template triangularView<Upper>() * res;
|
res = res.template triangularView<Upper>() * res;
|
||||||
}
|
}
|
||||||
compute2x2(res, m_p);
|
compute2x2(res, m_p);
|
||||||
@ -237,19 +291,28 @@ template<typename MatrixType>
|
|||||||
inline typename MatrixPowerAtomic<MatrixType>::ComplexScalar
|
inline typename MatrixPowerAtomic<MatrixType>::ComplexScalar
|
||||||
MatrixPowerAtomic<MatrixType>::computeSuperDiag(const ComplexScalar& curr, const ComplexScalar& prev, RealScalar p)
|
MatrixPowerAtomic<MatrixType>::computeSuperDiag(const ComplexScalar& curr, const ComplexScalar& prev, RealScalar p)
|
||||||
{
|
{
|
||||||
ComplexScalar logCurr = std::log(curr);
|
using std::ceil;
|
||||||
ComplexScalar logPrev = std::log(prev);
|
using std::exp;
|
||||||
int unwindingNumber = std::ceil((numext::imag(logCurr - logPrev) - M_PI) / (2*M_PI));
|
using std::log;
|
||||||
|
using std::sinh;
|
||||||
|
|
||||||
|
ComplexScalar logCurr = log(curr);
|
||||||
|
ComplexScalar logPrev = log(prev);
|
||||||
|
int unwindingNumber = ceil((numext::imag(logCurr - logPrev) - M_PI) / (2*M_PI));
|
||||||
ComplexScalar w = numext::atanh2(curr - prev, curr + prev) + ComplexScalar(0, M_PI*unwindingNumber);
|
ComplexScalar w = numext::atanh2(curr - prev, curr + prev) + ComplexScalar(0, M_PI*unwindingNumber);
|
||||||
return RealScalar(2) * std::exp(RealScalar(0.5) * p * (logCurr + logPrev)) * std::sinh(p * w) / (curr - prev);
|
return RealScalar(2) * exp(RealScalar(0.5) * p * (logCurr + logPrev)) * sinh(p * w) / (curr - prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename MatrixType>
|
template<typename MatrixType>
|
||||||
inline typename MatrixPowerAtomic<MatrixType>::RealScalar
|
inline typename MatrixPowerAtomic<MatrixType>::RealScalar
|
||||||
MatrixPowerAtomic<MatrixType>::computeSuperDiag(RealScalar curr, RealScalar prev, RealScalar p)
|
MatrixPowerAtomic<MatrixType>::computeSuperDiag(RealScalar curr, RealScalar prev, RealScalar p)
|
||||||
{
|
{
|
||||||
|
using std::exp;
|
||||||
|
using std::log;
|
||||||
|
using std::sinh;
|
||||||
|
|
||||||
RealScalar w = numext::atanh2(curr - prev, curr + prev);
|
RealScalar w = numext::atanh2(curr - prev, curr + prev);
|
||||||
return 2 * std::exp(p * (std::log(curr) + std::log(prev)) / 2) * std::sinh(p * w) / (curr - prev);
|
return 2 * exp(p * (log(curr) + log(prev)) / 2) * sinh(p * w) / (curr - prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -272,15 +335,9 @@ MatrixPowerAtomic<MatrixType>::computeSuperDiag(RealScalar curr, RealScalar prev
|
|||||||
* Output: \verbinclude MatrixPower_optimal.out
|
* Output: \verbinclude MatrixPower_optimal.out
|
||||||
*/
|
*/
|
||||||
template<typename MatrixType>
|
template<typename MatrixType>
|
||||||
class MatrixPower
|
class MatrixPower : internal::noncopyable
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
enum {
|
|
||||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
|
||||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime,
|
|
||||||
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
|
|
||||||
MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
|
|
||||||
};
|
|
||||||
typedef typename MatrixType::Scalar Scalar;
|
typedef typename MatrixType::Scalar Scalar;
|
||||||
typedef typename MatrixType::RealScalar RealScalar;
|
typedef typename MatrixType::RealScalar RealScalar;
|
||||||
typedef typename MatrixType::Index Index;
|
typedef typename MatrixType::Index Index;
|
||||||
@ -294,7 +351,11 @@ class MatrixPower
|
|||||||
* The class stores a reference to A, so it should not be changed
|
* The class stores a reference to A, so it should not be changed
|
||||||
* (or destroyed) before evaluation.
|
* (or destroyed) before evaluation.
|
||||||
*/
|
*/
|
||||||
explicit MatrixPower(const MatrixType& A) : m_A(A), m_conditionNumber(0)
|
explicit MatrixPower(const MatrixType& A) :
|
||||||
|
m_A(A),
|
||||||
|
m_conditionNumber(0),
|
||||||
|
m_rank(A.cols()),
|
||||||
|
m_nulls(0)
|
||||||
{ eigen_assert(A.rows() == A.cols()); }
|
{ eigen_assert(A.rows() == A.cols()); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -304,8 +365,8 @@ class MatrixPower
|
|||||||
* \return The expression \f$ A^p \f$, where A is specified in the
|
* \return The expression \f$ A^p \f$, where A is specified in the
|
||||||
* constructor.
|
* constructor.
|
||||||
*/
|
*/
|
||||||
const MatrixPowerRetval<MatrixType> operator()(RealScalar p)
|
const MatrixPowerParenthesesReturnValue<MatrixType> operator()(RealScalar p)
|
||||||
{ return MatrixPowerRetval<MatrixType>(*this, p); }
|
{ return MatrixPowerParenthesesReturnValue<MatrixType>(*this, p); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Compute the matrix power.
|
* \brief Compute the matrix power.
|
||||||
@ -322,21 +383,54 @@ class MatrixPower
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::complex<RealScalar> ComplexScalar;
|
typedef std::complex<RealScalar> ComplexScalar;
|
||||||
typedef Matrix<ComplexScalar, RowsAtCompileTime, ColsAtCompileTime, MatrixType::Options,
|
typedef Matrix<ComplexScalar, Dynamic, Dynamic, MatrixType::Options,
|
||||||
MaxRowsAtCompileTime, MaxColsAtCompileTime> ComplexMatrix;
|
MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime> ComplexMatrix;
|
||||||
|
|
||||||
|
/** \brief Reference to the base of matrix power. */
|
||||||
typename MatrixType::Nested m_A;
|
typename MatrixType::Nested m_A;
|
||||||
|
|
||||||
|
/** \brief Temporary storage. */
|
||||||
MatrixType m_tmp;
|
MatrixType m_tmp;
|
||||||
ComplexMatrix m_T, m_U, m_fT;
|
|
||||||
|
/** \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;
|
RealScalar m_conditionNumber;
|
||||||
|
|
||||||
RealScalar modfAndInit(RealScalar, RealScalar*);
|
/** \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);
|
||||||
|
|
||||||
|
/** \brief Perform Schur decomposition for fractional power. */
|
||||||
|
void initialize();
|
||||||
|
|
||||||
template<typename ResultType>
|
template<typename ResultType>
|
||||||
void computeIntPower(ResultType&, RealScalar);
|
void computeIntPower(ResultType& res, RealScalar p);
|
||||||
|
|
||||||
template<typename ResultType>
|
template<typename ResultType>
|
||||||
void computeFracPower(ResultType&, RealScalar);
|
void computeFracPower(ResultType& res, RealScalar p);
|
||||||
|
|
||||||
template<int Rows, int Cols, int Options, int MaxRows, int MaxCols>
|
template<int Rows, int Cols, int Options, int MaxRows, int MaxCols>
|
||||||
static void revertSchur(
|
static void revertSchur(
|
||||||
@ -355,59 +449,102 @@ template<typename MatrixType>
|
|||||||
template<typename ResultType>
|
template<typename ResultType>
|
||||||
void MatrixPower<MatrixType>::compute(ResultType& res, RealScalar p)
|
void MatrixPower<MatrixType>::compute(ResultType& res, RealScalar p)
|
||||||
{
|
{
|
||||||
|
using std::pow;
|
||||||
switch (cols()) {
|
switch (cols()) {
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
res(0,0) = std::pow(m_A.coeff(0,0), p);
|
res(0,0) = pow(m_A.coeff(0,0), p);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
RealScalar intpart, x = modfAndInit(p, &intpart);
|
RealScalar intpart;
|
||||||
|
split(p, intpart);
|
||||||
|
|
||||||
|
res = MatrixType::Identity(rows(), cols());
|
||||||
computeIntPower(res, intpart);
|
computeIntPower(res, intpart);
|
||||||
computeFracPower(res, x);
|
if (p) computeFracPower(res, p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename MatrixType>
|
template<typename MatrixType>
|
||||||
typename MatrixPower<MatrixType>::RealScalar
|
void MatrixPower<MatrixType>::split(RealScalar& p, RealScalar& intpart)
|
||||||
MatrixPower<MatrixType>::modfAndInit(RealScalar x, RealScalar* intpart)
|
|
||||||
{
|
{
|
||||||
typedef Array<RealScalar, RowsAtCompileTime, 1, ColMajor, MaxRowsAtCompileTime> RealArray;
|
using std::floor;
|
||||||
|
using std::pow;
|
||||||
|
|
||||||
*intpart = std::floor(x);
|
intpart = floor(p);
|
||||||
RealScalar res = x - *intpart;
|
p -= intpart;
|
||||||
|
|
||||||
if (!m_conditionNumber && res) {
|
// Perform Schur decomposition if it is not yet performed and the power is
|
||||||
const ComplexSchur<MatrixType> schurOfA(m_A);
|
// not an integer.
|
||||||
m_T = schurOfA.matrixT();
|
if (!m_conditionNumber && p)
|
||||||
m_U = schurOfA.matrixU();
|
initialize();
|
||||||
|
|
||||||
const RealArray absTdiag = m_T.diagonal().array().abs();
|
// Choose the more stable of intpart = floor(p) and intpart = ceil(p).
|
||||||
m_conditionNumber = absTdiag.maxCoeff() / absTdiag.minCoeff();
|
if (p > RealScalar(0.5) && p > (1-p) * pow(m_conditionNumber, p)) {
|
||||||
|
--p;
|
||||||
|
++intpart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename MatrixType>
|
||||||
|
void MatrixPower<MatrixType>::initialize()
|
||||||
|
{
|
||||||
|
const ComplexSchur<MatrixType> schurOfA(m_A);
|
||||||
|
JacobiRotation<ComplexScalar> rot;
|
||||||
|
ComplexScalar eigenvalue;
|
||||||
|
|
||||||
|
m_fT.resizeLike(m_A);
|
||||||
|
m_T = schurOfA.matrixT();
|
||||||
|
m_U = schurOfA.matrixU();
|
||||||
|
m_conditionNumber = m_T.diagonal().array().abs().maxCoeff() / m_T.diagonal().array().abs().minCoeff();
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res>RealScalar(0.5) && res>(1-res)*std::pow(m_conditionNumber, res)) {
|
m_nulls = rows() - m_rank;
|
||||||
--res;
|
if (m_nulls) {
|
||||||
++*intpart;
|
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));
|
||||||
}
|
}
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename MatrixType>
|
template<typename MatrixType>
|
||||||
template<typename ResultType>
|
template<typename ResultType>
|
||||||
void MatrixPower<MatrixType>::computeIntPower(ResultType& res, RealScalar p)
|
void MatrixPower<MatrixType>::computeIntPower(ResultType& res, RealScalar p)
|
||||||
{
|
{
|
||||||
RealScalar pp = std::abs(p);
|
using std::abs;
|
||||||
|
using std::fmod;
|
||||||
|
RealScalar pp = abs(p);
|
||||||
|
|
||||||
if (p<0) m_tmp = m_A.inverse();
|
if (p<0)
|
||||||
else m_tmp = m_A;
|
m_tmp = m_A.inverse();
|
||||||
|
else
|
||||||
|
m_tmp = m_A;
|
||||||
|
|
||||||
res = MatrixType::Identity(rows(), cols());
|
while (true) {
|
||||||
while (pp >= 1) {
|
if (fmod(pp, 2) >= 1)
|
||||||
if (std::fmod(pp, 2) >= 1)
|
|
||||||
res = m_tmp * res;
|
res = m_tmp * res;
|
||||||
m_tmp *= m_tmp;
|
|
||||||
pp /= 2;
|
pp /= 2;
|
||||||
|
if (pp < 1)
|
||||||
|
break;
|
||||||
|
m_tmp *= m_tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,12 +552,17 @@ template<typename MatrixType>
|
|||||||
template<typename ResultType>
|
template<typename ResultType>
|
||||||
void MatrixPower<MatrixType>::computeFracPower(ResultType& res, RealScalar p)
|
void MatrixPower<MatrixType>::computeFracPower(ResultType& res, RealScalar p)
|
||||||
{
|
{
|
||||||
if (p) {
|
Block<ComplexMatrix,Dynamic,Dynamic> blockTp(m_fT, 0, 0, m_rank, m_rank);
|
||||||
eigen_assert(m_conditionNumber);
|
eigen_assert(m_conditionNumber);
|
||||||
MatrixPowerAtomic<ComplexMatrix>(m_T, p).compute(m_fT);
|
eigen_assert(m_rank + m_nulls == rows());
|
||||||
revertSchur(m_tmp, m_fT, m_U);
|
|
||||||
res = m_tmp * res;
|
MatrixPowerAtomic<ComplexMatrix>(m_T.topLeftCorner(m_rank, m_rank), p).compute(blockTp);
|
||||||
|
if (m_nulls) {
|
||||||
|
m_fT.topRightCorner(m_rank, m_nulls) = m_T.topLeftCorner(m_rank, m_rank).template triangularView<Upper>()
|
||||||
|
.solve(blockTp * m_T.topRightCorner(m_rank, m_nulls));
|
||||||
}
|
}
|
||||||
|
revertSchur(m_tmp, m_fT, m_U);
|
||||||
|
res = m_tmp * res;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename MatrixType>
|
template<typename MatrixType>
|
||||||
@ -464,7 +606,7 @@ class MatrixPowerReturnValue : public ReturnByValue< MatrixPowerReturnValue<Deri
|
|||||||
* \brief Constructor.
|
* \brief Constructor.
|
||||||
*
|
*
|
||||||
* \param[in] A %Matrix (expression), the base of the matrix power.
|
* \param[in] A %Matrix (expression), the base of the matrix power.
|
||||||
* \param[in] p scalar, the exponent 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)
|
MatrixPowerReturnValue(const Derived& A, RealScalar p) : m_A(A), m_p(p)
|
||||||
{ }
|
{ }
|
||||||
@ -485,25 +627,83 @@ class MatrixPowerReturnValue : public ReturnByValue< MatrixPowerReturnValue<Deri
|
|||||||
private:
|
private:
|
||||||
const Derived& m_A;
|
const Derived& m_A;
|
||||||
const RealScalar m_p;
|
const RealScalar m_p;
|
||||||
MatrixPowerReturnValue& operator=(const MatrixPowerReturnValue&);
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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:
|
||||||
|
typedef typename Derived::PlainObject PlainObject;
|
||||||
|
typedef typename std::complex<typename Derived::RealScalar> ComplexScalar;
|
||||||
|
typedef typename Derived::Index Index;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \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>
|
||||||
|
inline void evalTo(ResultType& res) const
|
||||||
|
{ res = (m_p * m_A.log()).exp(); }
|
||||||
|
|
||||||
|
Index rows() const { return m_A.rows(); }
|
||||||
|
Index cols() const { return m_A.cols(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Derived& m_A;
|
||||||
|
const ComplexScalar m_p;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
template<typename MatrixPowerType>
|
template<typename MatrixPowerType>
|
||||||
struct traits< MatrixPowerRetval<MatrixPowerType> >
|
struct traits< MatrixPowerParenthesesReturnValue<MatrixPowerType> >
|
||||||
{ typedef typename MatrixPowerType::PlainObject ReturnType; };
|
{ typedef typename MatrixPowerType::PlainObject ReturnType; };
|
||||||
|
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
struct traits< MatrixPowerReturnValue<Derived> >
|
struct traits< MatrixPowerReturnValue<Derived> >
|
||||||
{ typedef typename Derived::PlainObject ReturnType; };
|
{ typedef typename Derived::PlainObject ReturnType; };
|
||||||
|
|
||||||
|
template<typename Derived>
|
||||||
|
struct traits< MatrixComplexPowerReturnValue<Derived> >
|
||||||
|
{ typedef typename Derived::PlainObject ReturnType; };
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
const MatrixPowerReturnValue<Derived> MatrixBase<Derived>::pow(const RealScalar& p) const
|
const MatrixPowerReturnValue<Derived> MatrixBase<Derived>::pow(const RealScalar& p) const
|
||||||
{ return MatrixPowerReturnValue<Derived>(derived(), p); }
|
{ return MatrixPowerReturnValue<Derived>(derived(), p); }
|
||||||
|
|
||||||
|
template<typename Derived>
|
||||||
|
const MatrixComplexPowerReturnValue<Derived> MatrixBase<Derived>::pow(const std::complex<RealScalar>& p) const
|
||||||
|
{ return MatrixComplexPowerReturnValue<Derived>(derived(), p); }
|
||||||
|
|
||||||
} // namespace Eigen
|
} // namespace Eigen
|
||||||
|
|
||||||
#endif // EIGEN_MATRIX_POWER
|
#endif // EIGEN_MATRIX_POWER
|
||||||
|
@ -24,7 +24,7 @@ namespace Eigen {
|
|||||||
* \sa MatrixSquareRoot, MatrixSquareRootTriangular
|
* \sa MatrixSquareRoot, MatrixSquareRootTriangular
|
||||||
*/
|
*/
|
||||||
template <typename MatrixType>
|
template <typename MatrixType>
|
||||||
class MatrixSquareRootQuasiTriangular
|
class MatrixSquareRootQuasiTriangular : internal::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ class MatrixSquareRootQuasiTriangular
|
|||||||
* The class stores a reference to \p A, so it should not be
|
* The class stores a reference to \p A, so it should not be
|
||||||
* changed (or destroyed) before compute() is called.
|
* changed (or destroyed) before compute() is called.
|
||||||
*/
|
*/
|
||||||
MatrixSquareRootQuasiTriangular(const MatrixType& A)
|
explicit MatrixSquareRootQuasiTriangular(const MatrixType& A)
|
||||||
: m_A(A)
|
: m_A(A)
|
||||||
{
|
{
|
||||||
eigen_assert(A.rows() == A.cols());
|
eigen_assert(A.rows() == A.cols());
|
||||||
@ -253,10 +253,10 @@ void MatrixSquareRootQuasiTriangular<MatrixType>
|
|||||||
* \sa MatrixSquareRoot, MatrixSquareRootQuasiTriangular
|
* \sa MatrixSquareRoot, MatrixSquareRootQuasiTriangular
|
||||||
*/
|
*/
|
||||||
template <typename MatrixType>
|
template <typename MatrixType>
|
||||||
class MatrixSquareRootTriangular
|
class MatrixSquareRootTriangular : internal::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MatrixSquareRootTriangular(const MatrixType& A)
|
explicit MatrixSquareRootTriangular(const MatrixType& A)
|
||||||
: m_A(A)
|
: m_A(A)
|
||||||
{
|
{
|
||||||
eigen_assert(A.rows() == A.cols());
|
eigen_assert(A.rows() == A.cols());
|
||||||
@ -321,7 +321,7 @@ class MatrixSquareRoot
|
|||||||
* The class stores a reference to \p A, so it should not be
|
* The class stores a reference to \p A, so it should not be
|
||||||
* changed (or destroyed) before compute() is called.
|
* changed (or destroyed) before compute() is called.
|
||||||
*/
|
*/
|
||||||
MatrixSquareRoot(const MatrixType& A);
|
explicit MatrixSquareRoot(const MatrixType& A);
|
||||||
|
|
||||||
/** \brief Compute the matrix square root
|
/** \brief Compute the matrix square root
|
||||||
*
|
*
|
||||||
@ -341,7 +341,7 @@ class MatrixSquareRoot<MatrixType, 0>
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MatrixSquareRoot(const MatrixType& A)
|
explicit MatrixSquareRoot(const MatrixType& A)
|
||||||
: m_A(A)
|
: m_A(A)
|
||||||
{
|
{
|
||||||
eigen_assert(A.rows() == A.cols());
|
eigen_assert(A.rows() == A.cols());
|
||||||
@ -370,11 +370,11 @@ class MatrixSquareRoot<MatrixType, 0>
|
|||||||
// ********** Partial specialization for complex matrices **********
|
// ********** Partial specialization for complex matrices **********
|
||||||
|
|
||||||
template <typename MatrixType>
|
template <typename MatrixType>
|
||||||
class MatrixSquareRoot<MatrixType, 1>
|
class MatrixSquareRoot<MatrixType, 1> : internal::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MatrixSquareRoot(const MatrixType& A)
|
explicit MatrixSquareRoot(const MatrixType& A)
|
||||||
: m_A(A)
|
: m_A(A)
|
||||||
{
|
{
|
||||||
eigen_assert(A.rows() == A.cols());
|
eigen_assert(A.rows() == A.cols());
|
||||||
@ -422,7 +422,7 @@ template<typename Derived> class MatrixSquareRootReturnValue
|
|||||||
* \param[in] src %Matrix (expression) forming the argument of the
|
* \param[in] src %Matrix (expression) forming the argument of the
|
||||||
* matrix square root.
|
* matrix square root.
|
||||||
*/
|
*/
|
||||||
MatrixSquareRootReturnValue(const Derived& src) : m_src(src) { }
|
explicit MatrixSquareRootReturnValue(const Derived& src) : m_src(src) { }
|
||||||
|
|
||||||
/** \brief Compute the matrix square root.
|
/** \brief Compute the matrix square root.
|
||||||
*
|
*
|
||||||
@ -442,8 +442,6 @@ template<typename Derived> class MatrixSquareRootReturnValue
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
const Derived& m_src;
|
const Derived& m_src;
|
||||||
private:
|
|
||||||
MatrixSquareRootReturnValue& operator=(const MatrixSquareRootReturnValue&);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -16,7 +16,7 @@ namespace Eigen {
|
|||||||
* \brief Stem functions corresponding to standard mathematical functions.
|
* \brief Stem functions corresponding to standard mathematical functions.
|
||||||
*/
|
*/
|
||||||
template <typename Scalar>
|
template <typename Scalar>
|
||||||
class StdStemFunctions
|
class StdStemFunctions : internal::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -107,31 +107,34 @@ void test_kronecker_product()
|
|||||||
|
|
||||||
SparseMatrix<double,RowMajor> SM_row_a(SM_a), SM_row_b(SM_b);
|
SparseMatrix<double,RowMajor> SM_row_a(SM_a), SM_row_b(SM_b);
|
||||||
|
|
||||||
// test kroneckerProduct(DM_block,DM,DM_fixedSize)
|
// test DM_fixedSize = kroneckerProduct(DM_block,DM)
|
||||||
Matrix<double, 6, 6> DM_fix_ab = kroneckerProduct(DM_a.topLeftCorner<2,3>(),DM_b);
|
Matrix<double, 6, 6> DM_fix_ab = kroneckerProduct(DM_a.topLeftCorner<2,3>(),DM_b);
|
||||||
|
|
||||||
CALL_SUBTEST(check_kronecker_product(DM_fix_ab));
|
CALL_SUBTEST(check_kronecker_product(DM_fix_ab));
|
||||||
|
CALL_SUBTEST(check_kronecker_product(kroneckerProduct(DM_a.topLeftCorner<2,3>(),DM_b)));
|
||||||
|
|
||||||
for(int i=0;i<DM_fix_ab.rows();++i)
|
for(int i=0;i<DM_fix_ab.rows();++i)
|
||||||
for(int j=0;j<DM_fix_ab.cols();++j)
|
for(int j=0;j<DM_fix_ab.cols();++j)
|
||||||
VERIFY_IS_APPROX(kroneckerProduct(DM_a,DM_b).coeff(i,j), DM_fix_ab(i,j));
|
VERIFY_IS_APPROX(kroneckerProduct(DM_a,DM_b).coeff(i,j), DM_fix_ab(i,j));
|
||||||
|
|
||||||
// test kroneckerProduct(DM,DM,DM_block)
|
// test DM_block = kroneckerProduct(DM,DM)
|
||||||
MatrixXd DM_block_ab(10,15);
|
MatrixXd DM_block_ab(10,15);
|
||||||
DM_block_ab.block<6,6>(2,5) = kroneckerProduct(DM_a,DM_b);
|
DM_block_ab.block<6,6>(2,5) = kroneckerProduct(DM_a,DM_b);
|
||||||
CALL_SUBTEST(check_kronecker_product(DM_block_ab.block<6,6>(2,5)));
|
CALL_SUBTEST(check_kronecker_product(DM_block_ab.block<6,6>(2,5)));
|
||||||
|
|
||||||
// test kroneckerProduct(DM,DM,DM)
|
// test DM = kroneckerProduct(DM,DM)
|
||||||
MatrixXd DM_ab = kroneckerProduct(DM_a,DM_b);
|
MatrixXd DM_ab = kroneckerProduct(DM_a,DM_b);
|
||||||
CALL_SUBTEST(check_kronecker_product(DM_ab));
|
CALL_SUBTEST(check_kronecker_product(DM_ab));
|
||||||
|
CALL_SUBTEST(check_kronecker_product(kroneckerProduct(DM_a,DM_b)));
|
||||||
|
|
||||||
// test kroneckerProduct(SM,DM,SM)
|
// test SM = kroneckerProduct(SM,DM)
|
||||||
SparseMatrix<double> SM_ab = kroneckerProduct(SM_a,DM_b);
|
SparseMatrix<double> SM_ab = kroneckerProduct(SM_a,DM_b);
|
||||||
CALL_SUBTEST(check_kronecker_product(SM_ab));
|
CALL_SUBTEST(check_kronecker_product(SM_ab));
|
||||||
SparseMatrix<double,RowMajor> SM_ab2 = kroneckerProduct(SM_a,DM_b);
|
SparseMatrix<double,RowMajor> SM_ab2 = kroneckerProduct(SM_a,DM_b);
|
||||||
CALL_SUBTEST(check_kronecker_product(SM_ab2));
|
CALL_SUBTEST(check_kronecker_product(SM_ab2));
|
||||||
|
CALL_SUBTEST(check_kronecker_product(kroneckerProduct(SM_a,DM_b)));
|
||||||
|
|
||||||
// test kroneckerProduct(DM,SM,SM)
|
// test SM = kroneckerProduct(DM,SM)
|
||||||
SM_ab.setZero();
|
SM_ab.setZero();
|
||||||
SM_ab.insert(0,0)=37.0;
|
SM_ab.insert(0,0)=37.0;
|
||||||
SM_ab = kroneckerProduct(DM_a,SM_b);
|
SM_ab = kroneckerProduct(DM_a,SM_b);
|
||||||
@ -140,8 +143,9 @@ void test_kronecker_product()
|
|||||||
SM_ab2.insert(0,0)=37.0;
|
SM_ab2.insert(0,0)=37.0;
|
||||||
SM_ab2 = kroneckerProduct(DM_a,SM_b);
|
SM_ab2 = kroneckerProduct(DM_a,SM_b);
|
||||||
CALL_SUBTEST(check_kronecker_product(SM_ab2));
|
CALL_SUBTEST(check_kronecker_product(SM_ab2));
|
||||||
|
CALL_SUBTEST(check_kronecker_product(kroneckerProduct(DM_a,SM_b)));
|
||||||
|
|
||||||
// test kroneckerProduct(SM,SM,SM)
|
// test SM = kroneckerProduct(SM,SM)
|
||||||
SM_ab.resize(2,33);
|
SM_ab.resize(2,33);
|
||||||
SM_ab.insert(0,0)=37.0;
|
SM_ab.insert(0,0)=37.0;
|
||||||
SM_ab = kroneckerProduct(SM_a,SM_b);
|
SM_ab = kroneckerProduct(SM_a,SM_b);
|
||||||
@ -150,8 +154,9 @@ void test_kronecker_product()
|
|||||||
SM_ab2.insert(0,0)=37.0;
|
SM_ab2.insert(0,0)=37.0;
|
||||||
SM_ab2 = kroneckerProduct(SM_a,SM_b);
|
SM_ab2 = kroneckerProduct(SM_a,SM_b);
|
||||||
CALL_SUBTEST(check_kronecker_product(SM_ab2));
|
CALL_SUBTEST(check_kronecker_product(SM_ab2));
|
||||||
|
CALL_SUBTEST(check_kronecker_product(kroneckerProduct(SM_a,SM_b)));
|
||||||
|
|
||||||
// test kroneckerProduct(SM,SM,SM) with sparse pattern
|
// test SM = kroneckerProduct(SM,SM) with sparse pattern
|
||||||
SM_a.resize(4,5);
|
SM_a.resize(4,5);
|
||||||
SM_b.resize(3,2);
|
SM_b.resize(3,2);
|
||||||
SM_a.resizeNonZeros(0);
|
SM_a.resizeNonZeros(0);
|
||||||
@ -169,7 +174,7 @@ void test_kronecker_product()
|
|||||||
SM_ab = kroneckerProduct(SM_a,SM_b);
|
SM_ab = kroneckerProduct(SM_a,SM_b);
|
||||||
CALL_SUBTEST(check_sparse_kronecker_product(SM_ab));
|
CALL_SUBTEST(check_sparse_kronecker_product(SM_ab));
|
||||||
|
|
||||||
// test dimension of result of kroneckerProduct(DM,DM,DM)
|
// test dimension of result of DM = kroneckerProduct(DM,DM)
|
||||||
MatrixXd DM_a2(2,1);
|
MatrixXd DM_a2(2,1);
|
||||||
MatrixXd DM_b2(5,4);
|
MatrixXd DM_b2(5,4);
|
||||||
MatrixXd DM_ab2 = kroneckerProduct(DM_a2,DM_b2);
|
MatrixXd DM_ab2 = kroneckerProduct(DM_a2,DM_b2);
|
||||||
|
@ -10,27 +10,48 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include <unsupported/Eigen/MatrixFunctions>
|
#include <unsupported/Eigen/MatrixFunctions>
|
||||||
|
|
||||||
|
// For complex matrices, any matrix is fine.
|
||||||
|
template<typename MatrixType, int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex>
|
||||||
|
struct processTriangularMatrix
|
||||||
|
{
|
||||||
|
static void run(MatrixType&, MatrixType&, const MatrixType&)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
// For real matrices, make sure none of the eigenvalues are negative.
|
||||||
|
template<typename MatrixType>
|
||||||
|
struct processTriangularMatrix<MatrixType,0>
|
||||||
|
{
|
||||||
|
static void run(MatrixType& m, MatrixType& T, const MatrixType& U)
|
||||||
|
{
|
||||||
|
typedef typename MatrixType::Index Index;
|
||||||
|
const Index size = m.cols();
|
||||||
|
|
||||||
|
for (Index i=0; i < size; ++i) {
|
||||||
|
if (i == size - 1 || T.coeff(i+1,i) == 0)
|
||||||
|
T.coeffRef(i,i) = std::abs(T.coeff(i,i));
|
||||||
|
else
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
m = U * T * U.transpose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename MatrixType, int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex>
|
template <typename MatrixType, int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex>
|
||||||
struct generateTestMatrix;
|
struct generateTestMatrix;
|
||||||
|
|
||||||
// for real matrices, make sure none of the eigenvalues are negative
|
|
||||||
template <typename MatrixType>
|
template <typename MatrixType>
|
||||||
struct generateTestMatrix<MatrixType,0>
|
struct generateTestMatrix<MatrixType,0>
|
||||||
{
|
{
|
||||||
static void run(MatrixType& result, typename MatrixType::Index size)
|
static void run(MatrixType& result, typename MatrixType::Index size)
|
||||||
{
|
{
|
||||||
MatrixType mat = MatrixType::Random(size, size);
|
result = MatrixType::Random(size, size);
|
||||||
EigenSolver<MatrixType> es(mat);
|
RealSchur<MatrixType> schur(result);
|
||||||
typename EigenSolver<MatrixType>::EigenvalueType eivals = es.eigenvalues();
|
MatrixType T = schur.matrixT();
|
||||||
for (typename MatrixType::Index i = 0; i < size; ++i) {
|
processTriangularMatrix<MatrixType>::run(result, T, schur.matrixU());
|
||||||
if (eivals(i).imag() == 0 && eivals(i).real() < 0)
|
|
||||||
eivals(i) = -eivals(i);
|
|
||||||
}
|
|
||||||
result = (es.eigenvectors() * eivals.asDiagonal() * es.eigenvectors().inverse()).real();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// for complex matrices, any matrix is fine
|
|
||||||
template <typename MatrixType>
|
template <typename MatrixType>
|
||||||
struct generateTestMatrix<MatrixType,1>
|
struct generateTestMatrix<MatrixType,1>
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// This file is part of Eigen, a lightweight C++ template library
|
// This file is part of Eigen, a lightweight C++ template library
|
||||||
// for linear algebra.
|
// for linear algebra.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2012 Chen-Pang He <jdh8@ms63.hinet.net>
|
// Copyright (C) 2012, 2013 Chen-Pang He <jdh8@ms63.hinet.net>
|
||||||
//
|
//
|
||||||
// This Source Code Form is subject to the terms of the Mozilla
|
// 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
|
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||||
@ -9,33 +9,6 @@
|
|||||||
|
|
||||||
#include "matrix_functions.h"
|
#include "matrix_functions.h"
|
||||||
|
|
||||||
template <typename MatrixType, int IsComplex = NumTraits<typename MatrixType::Scalar>::IsComplex>
|
|
||||||
struct generateTriangularMatrix;
|
|
||||||
|
|
||||||
// for real matrices, make sure none of the eigenvalues are negative
|
|
||||||
template <typename MatrixType>
|
|
||||||
struct generateTriangularMatrix<MatrixType,0>
|
|
||||||
{
|
|
||||||
static void run(MatrixType& result, typename MatrixType::Index size)
|
|
||||||
{
|
|
||||||
result.resize(size, size);
|
|
||||||
result.template triangularView<Upper>() = MatrixType::Random(size, size);
|
|
||||||
for (typename MatrixType::Index i = 0; i < size; ++i)
|
|
||||||
result.coeffRef(i,i) = std::abs(result.coeff(i,i));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// for complex matrices, any matrix is fine
|
|
||||||
template <typename MatrixType>
|
|
||||||
struct generateTriangularMatrix<MatrixType,1>
|
|
||||||
{
|
|
||||||
static void run(MatrixType& result, typename MatrixType::Index size)
|
|
||||||
{
|
|
||||||
result.resize(size, size);
|
|
||||||
result.template triangularView<Upper>() = MatrixType::Random(size, size);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void test2dRotation(double tol)
|
void test2dRotation(double tol)
|
||||||
{
|
{
|
||||||
@ -53,7 +26,7 @@ void test2dRotation(double tol)
|
|||||||
|
|
||||||
C = Apow(std::ldexp(angle,1) / M_PI);
|
C = Apow(std::ldexp(angle,1) / M_PI);
|
||||||
std::cout << "test2dRotation: i = " << i << " error powerm = " << relerr(C,B) << '\n';
|
std::cout << "test2dRotation: i = " << i << " error powerm = " << relerr(C,B) << '\n';
|
||||||
VERIFY(C.isApprox(B, static_cast<T>(tol)));
|
VERIFY(C.isApprox(B, tol));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,12 +48,26 @@ void test2dHyperbolicRotation(double tol)
|
|||||||
|
|
||||||
C = Apow(angle);
|
C = Apow(angle);
|
||||||
std::cout << "test2dHyperbolicRotation: i = " << i << " error powerm = " << relerr(C,B) << '\n';
|
std::cout << "test2dHyperbolicRotation: i = " << i << " error powerm = " << relerr(C,B) << '\n';
|
||||||
VERIFY(C.isApprox(B, static_cast<T>(tol)));
|
VERIFY(C.isApprox(B, tol));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void test3dRotation(double tol)
|
||||||
|
{
|
||||||
|
Matrix<T,3,1> v;
|
||||||
|
T angle;
|
||||||
|
|
||||||
|
for (int i=0; i<=20; ++i) {
|
||||||
|
v = Matrix<T,3,1>::Random();
|
||||||
|
v.normalize();
|
||||||
|
angle = pow(10, (i-10) / 5.);
|
||||||
|
VERIFY(AngleAxis<T>(angle, v).matrix().isApprox(AngleAxis<T>(1,v).matrix().pow(angle), tol));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename MatrixType>
|
template<typename MatrixType>
|
||||||
void testExponentLaws(const MatrixType& m, double tol)
|
void testGeneral(const MatrixType& m, double tol)
|
||||||
{
|
{
|
||||||
typedef typename MatrixType::RealScalar RealScalar;
|
typedef typename MatrixType::RealScalar RealScalar;
|
||||||
MatrixType m1, m2, m3, m4, m5;
|
MatrixType m1, m2, m3, m4, m5;
|
||||||
@ -97,19 +84,64 @@ void testExponentLaws(const MatrixType& m, double tol)
|
|||||||
|
|
||||||
m4 = mpow(x+y);
|
m4 = mpow(x+y);
|
||||||
m5.noalias() = m2 * m3;
|
m5.noalias() = m2 * m3;
|
||||||
VERIFY(m4.isApprox(m5, static_cast<RealScalar>(tol)));
|
VERIFY(m4.isApprox(m5, tol));
|
||||||
|
|
||||||
m4 = mpow(x*y);
|
m4 = mpow(x*y);
|
||||||
m5 = m2.pow(y);
|
m5 = m2.pow(y);
|
||||||
VERIFY(m4.isApprox(m5, static_cast<RealScalar>(tol)));
|
VERIFY(m4.isApprox(m5, tol));
|
||||||
|
|
||||||
m4 = (std::abs(x) * m1).pow(y);
|
m4 = (std::abs(x) * m1).pow(y);
|
||||||
m5 = std::pow(std::abs(x), y) * m3;
|
m5 = std::pow(std::abs(x), y) * m3;
|
||||||
VERIFY(m4.isApprox(m5, static_cast<RealScalar>(tol)));
|
VERIFY(m4.isApprox(m5, tol));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename MatrixType>
|
||||||
|
void testSingular(MatrixType m, double tol)
|
||||||
|
{
|
||||||
|
const int IsComplex = NumTraits<typename internal::traits<MatrixType>::Scalar>::IsComplex;
|
||||||
|
typedef typename internal::conditional< IsComplex, MatrixSquareRootTriangular<MatrixType>,
|
||||||
|
MatrixSquareRootQuasiTriangular<MatrixType> >::type SquareRootType;
|
||||||
|
typedef typename internal::conditional<IsComplex, TriangularView<MatrixType,Upper>, const MatrixType&>::type TriangularType;
|
||||||
|
typename internal::conditional< IsComplex, ComplexSchur<MatrixType>, RealSchur<MatrixType> >::type schur;
|
||||||
|
MatrixType T;
|
||||||
|
|
||||||
|
for (int i=0; i < g_repeat; ++i) {
|
||||||
|
m.setRandom();
|
||||||
|
m.col(0).fill(0);
|
||||||
|
|
||||||
|
schur.compute(m);
|
||||||
|
T = schur.matrixT();
|
||||||
|
const MatrixType& U = schur.matrixU();
|
||||||
|
processTriangularMatrix<MatrixType>::run(m, T, U);
|
||||||
|
MatrixPower<MatrixType> mpow(m);
|
||||||
|
|
||||||
|
SquareRootType(T).compute(T);
|
||||||
|
VERIFY(mpow(0.5).isApprox(U * (TriangularType(T) * U.adjoint()), tol));
|
||||||
|
|
||||||
|
SquareRootType(T).compute(T);
|
||||||
|
VERIFY(mpow(0.25).isApprox(U * (TriangularType(T) * U.adjoint()), tol));
|
||||||
|
|
||||||
|
SquareRootType(T).compute(T);
|
||||||
|
VERIFY(mpow(0.125).isApprox(U * (TriangularType(T) * U.adjoint()), tol));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename MatrixType>
|
||||||
|
void testLogThenExp(MatrixType m, double tol)
|
||||||
|
{
|
||||||
|
typedef typename MatrixType::Scalar Scalar;
|
||||||
|
Scalar x;
|
||||||
|
|
||||||
|
for (int i=0; i < g_repeat; ++i) {
|
||||||
|
generateTestMatrix<MatrixType>::run(m, m.rows());
|
||||||
|
x = internal::random<Scalar>();
|
||||||
|
VERIFY(m.pow(x).isApprox((x * m.log()).exp(), tol));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef Matrix<double,3,3,RowMajor> Matrix3dRowMajor;
|
typedef Matrix<double,3,3,RowMajor> Matrix3dRowMajor;
|
||||||
|
typedef Matrix<long double,3,3> Matrix3e;
|
||||||
typedef Matrix<long double,Dynamic,Dynamic> MatrixXe;
|
typedef Matrix<long double,Dynamic,Dynamic> MatrixXe;
|
||||||
|
|
||||||
void test_matrix_power()
|
void test_matrix_power()
|
||||||
@ -121,13 +153,46 @@ void test_matrix_power()
|
|||||||
CALL_SUBTEST_1(test2dHyperbolicRotation<float>(1e-5));
|
CALL_SUBTEST_1(test2dHyperbolicRotation<float>(1e-5));
|
||||||
CALL_SUBTEST_9(test2dHyperbolicRotation<long double>(1e-14));
|
CALL_SUBTEST_9(test2dHyperbolicRotation<long double>(1e-14));
|
||||||
|
|
||||||
CALL_SUBTEST_2(testExponentLaws(Matrix2d(), 1e-13));
|
CALL_SUBTEST_10(test3dRotation<double>(1e-13));
|
||||||
CALL_SUBTEST_7(testExponentLaws(Matrix3dRowMajor(), 1e-13));
|
CALL_SUBTEST_11(test3dRotation<float>(1e-5));
|
||||||
CALL_SUBTEST_3(testExponentLaws(Matrix4cd(), 1e-13));
|
CALL_SUBTEST_12(test3dRotation<long double>(1e-13));
|
||||||
CALL_SUBTEST_4(testExponentLaws(MatrixXd(8,8), 2e-12));
|
|
||||||
CALL_SUBTEST_1(testExponentLaws(Matrix2f(), 1e-4));
|
CALL_SUBTEST_2(testGeneral(Matrix2d(), 1e-13));
|
||||||
CALL_SUBTEST_5(testExponentLaws(Matrix3cf(), 1e-4));
|
CALL_SUBTEST_7(testGeneral(Matrix3dRowMajor(), 1e-13));
|
||||||
CALL_SUBTEST_8(testExponentLaws(Matrix4f(), 1e-4));
|
CALL_SUBTEST_3(testGeneral(Matrix4cd(), 1e-13));
|
||||||
CALL_SUBTEST_6(testExponentLaws(MatrixXf(2,2), 1e-3)); // see bug 614
|
CALL_SUBTEST_4(testGeneral(MatrixXd(8,8), 2e-12));
|
||||||
CALL_SUBTEST_9(testExponentLaws(MatrixXe(7,7), 1e-13));
|
CALL_SUBTEST_1(testGeneral(Matrix2f(), 1e-4));
|
||||||
|
CALL_SUBTEST_5(testGeneral(Matrix3cf(), 1e-4));
|
||||||
|
CALL_SUBTEST_8(testGeneral(Matrix4f(), 1e-4));
|
||||||
|
CALL_SUBTEST_6(testGeneral(MatrixXf(2,2), 1e-3)); // see bug 614
|
||||||
|
CALL_SUBTEST_9(testGeneral(MatrixXe(7,7), 1e-13));
|
||||||
|
CALL_SUBTEST_10(testGeneral(Matrix3d(), 1e-13));
|
||||||
|
CALL_SUBTEST_11(testGeneral(Matrix3f(), 1e-4));
|
||||||
|
CALL_SUBTEST_12(testGeneral(Matrix3e(), 1e-13));
|
||||||
|
|
||||||
|
CALL_SUBTEST_2(testSingular(Matrix2d(), 1e-13));
|
||||||
|
CALL_SUBTEST_7(testSingular(Matrix3dRowMajor(), 1e-13));
|
||||||
|
CALL_SUBTEST_3(testSingular(Matrix4cd(), 1e-13));
|
||||||
|
CALL_SUBTEST_4(testSingular(MatrixXd(8,8), 2e-12));
|
||||||
|
CALL_SUBTEST_1(testSingular(Matrix2f(), 1e-4));
|
||||||
|
CALL_SUBTEST_5(testSingular(Matrix3cf(), 1e-4));
|
||||||
|
CALL_SUBTEST_8(testSingular(Matrix4f(), 1e-4));
|
||||||
|
CALL_SUBTEST_6(testSingular(MatrixXf(2,2), 1e-3));
|
||||||
|
CALL_SUBTEST_9(testSingular(MatrixXe(7,7), 1e-13));
|
||||||
|
CALL_SUBTEST_10(testSingular(Matrix3d(), 1e-13));
|
||||||
|
CALL_SUBTEST_11(testSingular(Matrix3f(), 1e-4));
|
||||||
|
CALL_SUBTEST_12(testSingular(Matrix3e(), 1e-13));
|
||||||
|
|
||||||
|
CALL_SUBTEST_2(testLogThenExp(Matrix2d(), 1e-13));
|
||||||
|
CALL_SUBTEST_7(testLogThenExp(Matrix3dRowMajor(), 1e-13));
|
||||||
|
CALL_SUBTEST_3(testLogThenExp(Matrix4cd(), 1e-13));
|
||||||
|
CALL_SUBTEST_4(testLogThenExp(MatrixXd(8,8), 2e-12));
|
||||||
|
CALL_SUBTEST_1(testLogThenExp(Matrix2f(), 1e-4));
|
||||||
|
CALL_SUBTEST_5(testLogThenExp(Matrix3cf(), 1e-4));
|
||||||
|
CALL_SUBTEST_8(testLogThenExp(Matrix4f(), 1e-4));
|
||||||
|
CALL_SUBTEST_6(testLogThenExp(MatrixXf(2,2), 1e-3));
|
||||||
|
CALL_SUBTEST_9(testLogThenExp(MatrixXe(7,7), 1e-13));
|
||||||
|
CALL_SUBTEST_10(testLogThenExp(Matrix3d(), 1e-13));
|
||||||
|
CALL_SUBTEST_11(testLogThenExp(Matrix3f(), 1e-4));
|
||||||
|
CALL_SUBTEST_12(testLogThenExp(Matrix3e(), 1e-13));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user