diff options
129 files changed, 2382 insertions, 1224 deletions
diff --git a/Eigen/Cholesky b/Eigen/Cholesky index a0e0d146b..7d209966f 100644 --- a/Eigen/Cholesky +++ b/Eigen/Cholesky @@ -5,15 +5,6 @@ #include "src/Core/util/DisableMSVCWarnings.h" -// Note that EIGEN_HIDE_HEAVY_CODE has to be defined per module -#if (defined EIGEN_EXTERN_INSTANTIATIONS) && (EIGEN_EXTERN_INSTANTIATIONS>=2) - #ifndef EIGEN_HIDE_HEAVY_CODE - #define EIGEN_HIDE_HEAVY_CODE - #endif -#elif defined EIGEN_HIDE_HEAVY_CODE - #undef EIGEN_HIDE_HEAVY_CODE -#endif - namespace Eigen { /** \defgroup Cholesky_Module Cholesky module @@ -37,29 +28,6 @@ namespace Eigen { } // namespace Eigen -#define EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(MATRIXTYPE,PREFIX) \ - PREFIX template class LLT<MATRIXTYPE>; \ - PREFIX template class LDLT<MATRIXTYPE> - -#define EIGEN_CHOLESKY_MODULE_INSTANTIATE(PREFIX) \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(Matrix2f,PREFIX); \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(Matrix2d,PREFIX); \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(Matrix3f,PREFIX); \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(Matrix3d,PREFIX); \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(Matrix4f,PREFIX); \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(Matrix4d,PREFIX); \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(MatrixXf,PREFIX); \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(MatrixXd,PREFIX); \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(MatrixXcf,PREFIX); \ - EIGEN_CHOLESKY_MODULE_INSTANTIATE_TYPE(MatrixXcd,PREFIX) - -#ifdef EIGEN_EXTERN_INSTANTIATIONS - -namespace Eigen { - EIGEN_CHOLESKY_MODULE_INSTANTIATE(extern); -} // namespace Eigen -#endif - #include "src/Core/util/EnableMSVCWarnings.h" #endif // EIGEN_CHOLESKY_MODULE_H diff --git a/Eigen/Core b/Eigen/Core index 595e1cb89..70c2c2207 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -260,6 +260,7 @@ using std::size_t; #include "src/Core/Diagonal.h" #include "src/Core/DiagonalProduct.h" #include "src/Core/PermutationMatrix.h" +#include "src/Core/Transpositions.h" #include "src/Core/Redux.h" #include "src/Core/Visitor.h" #include "src/Core/Fuzzy.h" diff --git a/Eigen/Eigenvalues b/Eigen/Eigenvalues index f22a3bc30..5a9757ad5 100644 --- a/Eigen/Eigenvalues +++ b/Eigen/Eigenvalues @@ -10,15 +10,6 @@ #include "Householder" #include "LU" -// Note that EIGEN_HIDE_HEAVY_CODE has to be defined per module -#if (defined EIGEN_EXTERN_INSTANTIATIONS) && (EIGEN_EXTERN_INSTANTIATIONS>=2) - #ifndef EIGEN_HIDE_HEAVY_CODE - #define EIGEN_HIDE_HEAVY_CODE - #endif -#elif defined EIGEN_HIDE_HEAVY_CODE - #undef EIGEN_HIDE_HEAVY_CODE -#endif - namespace Eigen { /** \defgroup Eigenvalues_Module Eigenvalues module @@ -44,32 +35,6 @@ namespace Eigen { #include "src/Eigenvalues/ComplexEigenSolver.h" #include "src/Eigenvalues/MatrixBaseEigenvalues.h" -// declare all classes for a given matrix type -#define EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(MATRIXTYPE,PREFIX) \ - PREFIX template class Tridiagonalization<MATRIXTYPE>; \ - PREFIX template class HessenbergDecomposition<MATRIXTYPE>; \ - PREFIX template class SelfAdjointEigenSolver<MATRIXTYPE> - -// removed because it does not support complex yet -// PREFIX template class EigenSolver<MATRIXTYPE> - -// declare all class for all types -#define EIGEN_EIGENVALUES_MODULE_INSTANTIATE(PREFIX) \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(Matrix2f,PREFIX); \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(Matrix2d,PREFIX); \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(Matrix3f,PREFIX); \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(Matrix3d,PREFIX); \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(Matrix4f,PREFIX); \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(Matrix4d,PREFIX); \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(MatrixXf,PREFIX); \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(MatrixXd,PREFIX); \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(MatrixXcf,PREFIX); \ - EIGEN_EIGENVALUES_MODULE_INSTANTIATE_TYPE(MatrixXcd,PREFIX) - -#ifdef EIGEN_EXTERN_INSTANTIATIONS - EIGEN_EIGENVALUES_MODULE_INSTANTIATE(extern); -#endif // EIGEN_EXTERN_INSTANTIATIONS - } // namespace Eigen #include "src/Core/util/EnableMSVCWarnings.h" @@ -9,15 +9,6 @@ #include "Jacobi" #include "Householder" -// Note that EIGEN_HIDE_HEAVY_CODE has to be defined per module -#if (defined EIGEN_EXTERN_INSTANTIATIONS) && (EIGEN_EXTERN_INSTANTIATIONS>=2) - #ifndef EIGEN_HIDE_HEAVY_CODE - #define EIGEN_HIDE_HEAVY_CODE - #endif -#elif defined EIGEN_HIDE_HEAVY_CODE - #undef EIGEN_HIDE_HEAVY_CODE -#endif - namespace Eigen { /** \defgroup QR_Module QR module @@ -38,26 +29,6 @@ namespace Eigen { #include "src/QR/FullPivHouseholderQR.h" #include "src/QR/ColPivHouseholderQR.h" -// declare all classes for a given matrix type -#define EIGEN_QR_MODULE_INSTANTIATE_TYPE(MATRIXTYPE,PREFIX) \ - PREFIX template class HouseholderQR<MATRIXTYPE>; \ - -// declare all class for all types -#define EIGEN_QR_MODULE_INSTANTIATE(PREFIX) \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(Matrix2f,PREFIX); \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(Matrix2d,PREFIX); \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(Matrix3f,PREFIX); \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(Matrix3d,PREFIX); \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(Matrix4f,PREFIX); \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(Matrix4d,PREFIX); \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(MatrixXf,PREFIX); \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(MatrixXd,PREFIX); \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(MatrixXcf,PREFIX); \ - EIGEN_QR_MODULE_INSTANTIATE_TYPE(MatrixXcd,PREFIX) - -#ifdef EIGEN_EXTERN_INSTANTIATIONS - EIGEN_QR_MODULE_INSTANTIATE(extern); -#endif // EIGEN_EXTERN_INSTANTIATIONS } // namespace Eigen diff --git a/Eigen/src/Array/ArrayBase.h b/Eigen/src/Array/ArrayBase.h index ccbc77202..527bcd329 100644 --- a/Eigen/src/Array/ArrayBase.h +++ b/Eigen/src/Array/ArrayBase.h @@ -61,7 +61,7 @@ template<typename Derived> class ArrayBase typename NumTraits<typename ei_traits<Derived>::Scalar>::Real>::operator*; typedef typename ei_traits<Derived>::StorageKind StorageKind; - typedef typename ei_index<StorageKind>::type Index; + typedef typename ei_traits<Derived>::Index Index; typedef typename ei_traits<Derived>::Scalar Scalar; typedef typename ei_packet_traits<Scalar>::type PacketScalar; typedef typename NumTraits<Scalar>::Real RealScalar; diff --git a/Eigen/src/Array/Reverse.h b/Eigen/src/Array/Reverse.h index cca425142..2d7510902 100644 --- a/Eigen/src/Array/Reverse.h +++ b/Eigen/src/Array/Reverse.h @@ -84,6 +84,10 @@ template<typename MatrixType, int Direction> class Reverse EIGEN_DENSE_PUBLIC_INTERFACE(Reverse) using Base::IsRowMajor; + // next line is necessary because otherwise const version of operator() + // is hidden by non-const version defined in this file + using Base::operator(); + protected: enum { PacketSize = ei_packet_traits<Scalar>::size, @@ -106,6 +110,12 @@ template<typename MatrixType, int Direction> class Reverse inline Index rows() const { return m_matrix.rows(); } inline Index cols() const { return m_matrix.cols(); } + inline Scalar& operator()(Index row, Index col) + { + ei_assert(row >= 0 && row < rows() && col >= 0 && col < cols()); + return coeffRef(row, col); + } + inline Scalar& coeffRef(Index row, Index col) { return m_matrix.const_cast_derived().coeffRef(ReverseRow ? m_matrix.rows() - row - 1 : row, @@ -128,6 +138,12 @@ template<typename MatrixType, int Direction> class Reverse return m_matrix.const_cast_derived().coeffRef(m_matrix.size() - index - 1); } + inline Scalar& operator()(Index index) + { + ei_assert(index >= 0 && index < m_matrix.size()); + return coeffRef(index); + } + template<int LoadMode> inline const PacketScalar packet(Index row, Index col) const { diff --git a/Eigen/src/Array/VectorwiseOp.h b/Eigen/src/Array/VectorwiseOp.h index e338a9193..8926e7a04 100644 --- a/Eigen/src/Array/VectorwiseOp.h +++ b/Eigen/src/Array/VectorwiseOp.h @@ -92,7 +92,7 @@ class PartialReduxExpr : ei_no_assignment_operator, Index rows() const { return (Direction==Vertical ? 1 : m_matrix.rows()); } Index cols() const { return (Direction==Horizontal ? 1 : m_matrix.cols()); } - const Scalar coeff(Index i, Index j) const + EIGEN_STRONG_INLINE const Scalar coeff(Index i, Index j) const { if (Direction==Vertical) return m_functor(m_matrix.col(j)); @@ -113,15 +113,15 @@ class PartialReduxExpr : ei_no_assignment_operator, const MemberOp m_functor; }; -#define EIGEN_MEMBER_FUNCTOR(MEMBER,COST) \ - template <typename ResultType> \ - struct ei_member_##MEMBER { \ - EIGEN_EMPTY_STRUCT_CTOR(ei_member_##MEMBER) \ - typedef ResultType result_type; \ - template<typename Scalar, int Size> struct Cost \ - { enum { value = COST }; }; \ - template<typename XprType> \ - inline ResultType operator()(const XprType& mat) const \ +#define EIGEN_MEMBER_FUNCTOR(MEMBER,COST) \ + template <typename ResultType> \ + struct ei_member_##MEMBER { \ + EIGEN_EMPTY_STRUCT_CTOR(ei_member_##MEMBER) \ + typedef ResultType result_type; \ + template<typename Scalar, int Size> struct Cost \ + { enum { value = COST }; }; \ + template<typename XprType> \ + EIGEN_STRONG_INLINE ResultType operator()(const XprType& mat) const \ { return mat.MEMBER(); } \ } @@ -178,14 +178,16 @@ template<typename ExpressionType, int Direction> class VectorwiseOp public: typedef typename ExpressionType::Scalar Scalar; + typedef typename ExpressionType::RealScalar RealScalar; typedef typename ExpressionType::Index Index; typedef typename ei_meta_if<ei_must_nest_by_value<ExpressionType>::ret, ExpressionType, const ExpressionType&>::ret ExpressionTypeNested; - template<template<typename _Scalar> class Functor> struct ReturnType + template<template<typename _Scalar> class Functor, + typename Scalar=typename ei_traits<ExpressionType>::Scalar> struct ReturnType { typedef PartialReduxExpr<ExpressionType, - Functor<typename ei_traits<ExpressionType>::Scalar>, + Functor<Scalar>, Direction > Type; }; @@ -285,7 +287,7 @@ template<typename ExpressionType, int Direction> class VectorwiseOp * Output: \verbinclude PartialRedux_squaredNorm.out * * \sa DenseBase::squaredNorm() */ - const typename ReturnType<ei_member_squaredNorm>::Type squaredNorm() const + const typename ReturnType<ei_member_squaredNorm,RealScalar>::Type squaredNorm() const { return _expression(); } /** \returns a row (or column) vector expression of the norm @@ -295,7 +297,7 @@ template<typename ExpressionType, int Direction> class VectorwiseOp * Output: \verbinclude PartialRedux_norm.out * * \sa DenseBase::norm() */ - const typename ReturnType<ei_member_norm>::Type norm() const + const typename ReturnType<ei_member_norm,RealScalar>::Type norm() const { return _expression(); } @@ -304,7 +306,7 @@ template<typename ExpressionType, int Direction> class VectorwiseOp * blue's algorithm. * * \sa DenseBase::blueNorm() */ - const typename ReturnType<ei_member_blueNorm>::Type blueNorm() const + const typename ReturnType<ei_member_blueNorm,RealScalar>::Type blueNorm() const { return _expression(); } @@ -313,7 +315,7 @@ template<typename ExpressionType, int Direction> class VectorwiseOp * underflow and overflow. * * \sa DenseBase::stableNorm() */ - const typename ReturnType<ei_member_stableNorm>::Type stableNorm() const + const typename ReturnType<ei_member_stableNorm,RealScalar>::Type stableNorm() const { return _expression(); } @@ -322,7 +324,7 @@ template<typename ExpressionType, int Direction> class VectorwiseOp * underflow and overflow using a concatenation of hypot() calls. * * \sa DenseBase::hypotNorm() */ - const typename ReturnType<ei_member_hypotNorm>::Type hypotNorm() const + const typename ReturnType<ei_member_hypotNorm,RealScalar>::Type hypotNorm() const { return _expression(); } /** \returns a row (or column) vector expression of the sum @@ -380,8 +382,8 @@ template<typename ExpressionType, int Direction> class VectorwiseOp /** \returns a matrix expression * where each column (or row) are reversed. * - * Example: \include PartialRedux_reverse.cpp - * Output: \verbinclude PartialRedux_reverse.out + * Example: \include Vectorwise_reverse.cpp + * Output: \verbinclude Vectorwise_reverse.out * * \sa DenseBase::reverse() */ const Reverse<ExpressionType, Direction> reverse() const diff --git a/Eigen/src/Cholesky/LDLT.h b/Eigen/src/Cholesky/LDLT.h index a433f8d0f..e9fa4a5d2 100644 --- a/Eigen/src/Cholesky/LDLT.h +++ b/Eigen/src/Cholesky/LDLT.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr> +// Copyright (C) 2008-2010 Gael Guennebaud <g.gael@free.fr> // Copyright (C) 2009 Keir Mierle <mierle@gmail.com> // Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com> // @@ -27,11 +27,13 @@ #ifndef EIGEN_LDLT_H #define EIGEN_LDLT_H +template<typename MatrixType, int UpLo> struct LDLT_Traits; + /** \ingroup cholesky_Module * * \class LDLT * - * \brief Robust Cholesky decomposition of a matrix + * \brief Robust Cholesky decomposition of a matrix with pivoting * * \param MatrixType the type of the matrix of which to compute the LDL^T Cholesky decomposition * @@ -43,7 +45,7 @@ * zeros in the bottom right rank(A) - n submatrix. Avoiding the square root * on D also stabilizes the computation. * - * Remember that Cholesky decompositions are not rank-revealing. Also, do not use a Cholesky + * Remember that Cholesky decompositions are not rank-revealing. Also, do not use a Cholesky * decomposition to determine whether a system of equations has a solution. * * \sa MatrixBase::ldlt(), class LLT @@ -52,7 +54,7 @@ * Note that during the decomposition, only the upper triangular part of A is considered. Therefore, * the strict lower part does not have to store correct values. */ -template<typename _MatrixType> class LDLT +template<typename _MatrixType, int _UpLo> class LDLT { public: typedef _MatrixType MatrixType; @@ -61,20 +63,25 @@ template<typename _MatrixType> class LDLT ColsAtCompileTime = MatrixType::ColsAtCompileTime, Options = MatrixType::Options, MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime, - MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime + MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime, + UpLo = _UpLo }; typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar; typedef typename MatrixType::Index Index; - typedef typename ei_plain_col_type<MatrixType, Index>::type IntColVectorType; typedef Matrix<Scalar, RowsAtCompileTime, 1, Options, MaxRowsAtCompileTime, 1> TmpMatrixType; + typedef Transpositions<RowsAtCompileTime, MaxRowsAtCompileTime> TranspositionType; + typedef PermutationMatrix<RowsAtCompileTime, MaxRowsAtCompileTime> PermutationType; + + typedef LDLT_Traits<MatrixType,UpLo> Traits; + /** \brief Default Constructor. * * The default constructor is useful in cases in which the user intends to * perform decompositions via LDLT::compute(const MatrixType&). */ - LDLT() : m_matrix(), m_p(), m_transpositions(), m_isInitialized(false) {} + LDLT() : m_matrix(), m_transpositions(), m_isInitialized(false) {} /** \brief Default Constructor with memory preallocation * @@ -82,15 +89,15 @@ template<typename _MatrixType> class LDLT * according to the specified problem \a size. * \sa LDLT() */ - LDLT(Index size) : m_matrix(size, size), - m_p(size), - m_transpositions(size), - m_temporary(size), - m_isInitialized(false) {} + LDLT(Index size) + : m_matrix(size, size), + m_transpositions(size), + m_temporary(size), + m_isInitialized(false) + {} LDLT(const MatrixType& matrix) : m_matrix(matrix.rows(), matrix.cols()), - m_p(matrix.rows()), m_transpositions(matrix.rows()), m_temporary(matrix.rows()), m_isInitialized(false) @@ -98,21 +105,26 @@ template<typename _MatrixType> class LDLT compute(matrix); } - /** \returns the lower triangular matrix L */ - inline TriangularView<MatrixType, UnitLower> matrixL(void) const + /** \returns a view of the upper triangular matrix U */ + inline typename Traits::MatrixU matrixU() const { ei_assert(m_isInitialized && "LDLT is not initialized."); - return m_matrix; + return Traits::getU(m_matrix); } - /** \returns a vector of integers, whose size is the number of rows of the matrix being decomposed, - * representing the P permutation i.e. the permutation of the rows. For its precise meaning, - * see the examples given in the documentation of class FullPivLU. + /** \returns a view of the lower triangular matrix L */ + inline typename Traits::MatrixL matrixL() const + { + ei_assert(m_isInitialized && "LDLT is not initialized."); + return Traits::getL(m_matrix); + } + + /** \returns the permutation matrix P as a transposition sequence. */ - inline const IntColVectorType& permutationP() const + inline const TranspositionType& transpositionsP() const { ei_assert(m_isInitialized && "LDLT is not initialized."); - return m_p; + return m_transpositions; } /** \returns the coefficients of the diagonal matrix D */ @@ -157,7 +169,7 @@ template<typename _MatrixType> class LDLT LDLT& compute(const MatrixType& matrix); - /** \returns the LDLT decomposition matrix + /** \returns the internal LDLT decomposition matrix * * TODO: document the storage layout */ @@ -173,6 +185,7 @@ template<typename _MatrixType> class LDLT inline Index cols() const { return m_matrix.cols(); } protected: + /** \internal * Used to compute and store the Cholesky decomposition A = L D L^* = U^* D U. * The strict upper part is used during the decomposition, the strict lower @@ -180,118 +193,173 @@ template<typename _MatrixType> class LDLT * is not stored), and the diagonal entries correspond to D. */ MatrixType m_matrix; - IntColVectorType m_p; - IntColVectorType m_transpositions; // FIXME do we really need to store permanently the transpositions? + TranspositionType m_transpositions; TmpMatrixType m_temporary; - Index m_sign; + int m_sign; bool m_isInitialized; }; -/** Compute / recompute the LDLT decomposition A = L D L^* = U^* D U of \a matrix - */ -template<typename MatrixType> -LDLT<MatrixType>& LDLT<MatrixType>::compute(const MatrixType& a) -{ - ei_assert(a.rows()==a.cols()); - const Index size = a.rows(); - - m_matrix = a; - - m_p.resize(size); - m_transpositions.resize(size); - m_isInitialized = false; - - if (size <= 1) { - m_p.setZero(); - m_transpositions.setZero(); - m_sign = ei_real(a.coeff(0,0))>0 ? 1:-1; - m_isInitialized = true; - return *this; - } - - RealScalar cutoff = 0, biggest_in_corner; - - // By using a temorary, packet-aligned products are guarenteed. In the LLT - // case this is unnecessary because the diagonal is included and will always - // have optimal alignment. - m_temporary.resize(size); +template<int UpLo> struct ei_ldlt_inplace; - for (Index j = 0; j < size; ++j) +template<> struct ei_ldlt_inplace<Lower> +{ + template<typename MatrixType, typename TranspositionType, typename Workspace> + static bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, int* sign=0) { - // Find largest diagonal element - Index index_of_biggest_in_corner; - biggest_in_corner = m_matrix.diagonal().tail(size-j).cwiseAbs() - .maxCoeff(&index_of_biggest_in_corner); - index_of_biggest_in_corner += j; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + typedef typename MatrixType::Index Index; + ei_assert(mat.rows()==mat.cols()); + const Index size = mat.rows(); - if(j == 0) + if (size <= 1) { - // The biggest overall is the point of reference to which further diagonals - // are compared; if any diagonal is negligible compared - // to the largest overall, the algorithm bails. - cutoff = ei_abs(NumTraits<Scalar>::epsilon() * biggest_in_corner); - - m_sign = ei_real(m_matrix.diagonal().coeff(index_of_biggest_in_corner)) > 0 ? 1 : -1; + transpositions.setIdentity(); + if(sign) + *sign = ei_real(mat.coeff(0,0))>0 ? 1:-1; + return true; } - // Finish early if the matrix is not full rank. - if(biggest_in_corner < cutoff) - { - for(Index i = j; i < size; i++) m_transpositions.coeffRef(i) = i; - break; - } + RealScalar cutoff = 0, biggest_in_corner; - m_transpositions.coeffRef(j) = index_of_biggest_in_corner; - if(j != index_of_biggest_in_corner) + for (Index k = 0; k < size; ++k) { - m_matrix.row(j).swap(m_matrix.row(index_of_biggest_in_corner)); - m_matrix.col(j).swap(m_matrix.col(index_of_biggest_in_corner)); - } + // Find largest diagonal element + Index index_of_biggest_in_corner; + biggest_in_corner = mat.diagonal().tail(size-k).cwiseAbs().maxCoeff(&index_of_biggest_in_corner); + index_of_biggest_in_corner += k; - if (j == 0) { - m_matrix.row(0) = m_matrix.row(0).conjugate(); - m_matrix.col(0).tail(size-1) = m_matrix.row(0).tail(size-1) / m_matrix.coeff(0,0); - continue; - } + if(k == 0) + { + // The biggest overall is the point of reference to which further diagonals + // are compared; if any diagonal is negligible compared + // to the largest overall, the algorithm bails. + cutoff = ei_abs(NumTraits<Scalar>::epsilon() * biggest_in_corner); + + if(sign) + *sign = ei_real(mat.diagonal().coeff(index_of_biggest_in_corner)) > 0 ? 1 : -1; + } - RealScalar Djj = ei_real(m_matrix.coeff(j,j) - m_matrix.row(j).head(j).dot(m_matrix.col(j).head(j))); - m_matrix.coeffRef(j,j) = Djj; + // Finish early if the matrix is not full rank. + if(biggest_in_corner < cutoff) + { + for(Index i = k; i < size; i++) transpositions.coeffRef(i) = i; + break; + } - Index endSize = size - j - 1; - if (endSize > 0) { - m_temporary.tail(endSize).noalias() = m_matrix.block(j+1,0, endSize, j) - * m_matrix.col(j).head(j).conjugate(); + transpositions.coeffRef(k) = index_of_biggest_in_corner; + if(k != index_of_biggest_in_corner) + { + // apply the transposition while taking care to consider only + // the lower triangular part + Index s = size-index_of_biggest_in_corner-1; // trailing size after the biggest element + mat.row(k).head(k).swap(mat.row(index_of_biggest_in_corner).head(k)); + mat.col(k).tail(s).swap(mat.col(index_of_biggest_in_corner).tail(s)); + std::swap(mat.coeffRef(k,k),mat.coeffRef(index_of_biggest_in_corner,index_of_biggest_in_corner)); + for(int i=k+1;i<index_of_biggest_in_corner;++i) + { + Scalar tmp = mat.coeffRef(i,k); + mat.coeffRef(i,k) = ei_conj(mat.coeffRef(index_of_biggest_in_corner,i)); + mat.coeffRef(index_of_biggest_in_corner,i) = ei_conj(tmp); + } + if(NumTraits<Scalar>::IsComplex) + mat.coeffRef(index_of_biggest_in_corner,k) = ei_conj(mat.coeff(index_of_biggest_in_corner,k)); + } - m_matrix.row(j).tail(endSize) = m_matrix.row(j).tail(endSize).conjugate() - - m_temporary.tail(endSize).transpose(); + // partition the matrix: + // A00 | - | - + // lu = A10 | A11 | - + // A20 | A21 | A22 + Index rs = size - k - 1; + Block<MatrixType,Dynamic,1> A21(mat,k+1,k,rs,1); + Block<MatrixType,1,Dynamic> A10(mat,k,0,1,k); + Block<MatrixType,Dynamic,Dynamic> A20(mat,k+1,0,rs,k); - if(ei_abs(Djj) > cutoff) + if(k>0) { - m_matrix.col(j).tail(endSize) = m_matrix.row(j).tail(endSize) / Djj; + temp.head(k) = mat.diagonal().head(k).asDiagonal() * A10.adjoint(); + mat.coeffRef(k,k) -= (A10 * temp.head(k)).value(); + if(rs>0) + A21.noalias() -= A20 * temp.head(k); } + if((rs>0) && (ei_abs(mat.coeffRef(k,k)) > cutoff)) + A21 /= mat.coeffRef(k,k); } + + return true; } +}; - // Reverse applied swaps to get P matrix. - for(Index k = 0; k < size; ++k) m_p.coeffRef(k) = k; - for(Index k = size-1; k >= 0; --k) { - std::swap(m_p.coeffRef(k), m_p.coeffRef(m_transpositions.coeff(k))); +template<> struct ei_ldlt_inplace<Upper> +{ + template<typename MatrixType, typename TranspositionType, typename Workspace> + static EIGEN_STRONG_INLINE bool unblocked(MatrixType& mat, TranspositionType& transpositions, Workspace& temp, int* sign=0) + { + Transpose<MatrixType> matt(mat); + return ei_ldlt_inplace<Lower>::unblocked(matt, transpositions, temp, sign); } +}; + +template<typename MatrixType> struct LDLT_Traits<MatrixType,Lower> +{ + typedef TriangularView<MatrixType, UnitLower> MatrixL; + typedef TriangularView<typename MatrixType::AdjointReturnType, UnitUpper> MatrixU; + inline static MatrixL getL(const MatrixType& m) { return m; } + inline static MatrixU getU(const MatrixType& m) { return m.adjoint(); } +}; + +template<typename MatrixType> struct LDLT_Traits<MatrixType,Upper> +{ + typedef TriangularView<typename MatrixType::AdjointReturnType, UnitLower> MatrixL; + typedef TriangularView<MatrixType, UnitUpper> MatrixU; + inline static MatrixL getL(const MatrixType& m) { return m.adjoint(); } + inline static MatrixU getU(const MatrixType& m) { return m; } +}; + +/** Compute / recompute the LDLT decomposition A = L D L^* = U^* D U of \a matrix + */ +template<typename MatrixType, int _UpLo> +LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::compute(const MatrixType& a) +{ + ei_assert(a.rows()==a.cols()); + const Index size = a.rows(); + + m_matrix = a; + + m_transpositions.resize(size); + m_isInitialized = false; + m_temporary.resize(size); + + ei_ldlt_inplace<UpLo>::unblocked(m_matrix, m_transpositions, m_temporary, &m_sign); m_isInitialized = true; return *this; } -template<typename _MatrixType, typename Rhs> -struct ei_solve_retval<LDLT<_MatrixType>, Rhs> - : ei_solve_retval_base<LDLT<_MatrixType>, Rhs> +template<typename _MatrixType, int _UpLo, typename Rhs> +struct ei_solve_retval<LDLT<_MatrixType,_UpLo>, Rhs> + : ei_solve_retval_base<LDLT<_MatrixType,_UpLo>, Rhs> { - EIGEN_MAKE_SOLVE_HELPERS(LDLT<_MatrixType>,Rhs) + typedef LDLT<_MatrixType,_UpLo> LDLTType; + EIGEN_MAKE_SOLVE_HELPERS(LDLTType,Rhs) template<typename Dest> void evalTo(Dest& dst) const { - dst = rhs(); - dec().solveInPlace(dst); + ei_assert(rhs().rows() == dec().matrixLDLT().rows()); + // dst = P b + dst = dec().transpositionsP() * rhs(); + + // dst = L^-1 (P b) + dec().matrixL().solveInPlace(dst); + + // dst = D^-1 (L^-1 P b) + dst = dec().vectorD().asDiagonal().inverse() * dst; + + // dst = L^-T (D^-1 L^-1 P b) + dec().matrixU().solveInPlace(dst); + + // dst = P^-1 (L^-T D^-1 L^-1 P b) = A^-1 b + dst = dec().transpositionsP().transpose() * dst; } }; @@ -306,29 +374,15 @@ struct ei_solve_retval<LDLT<_MatrixType>, Rhs> * * \sa LDLT::solve(), MatrixBase::ldlt() */ -template<typename MatrixType> +template<typename MatrixType,int _UpLo> template<typename Derived> -bool LDLT<MatrixType>::solveInPlace(MatrixBase<Derived> &bAndX) const +bool LDLT<MatrixType,_UpLo>::solveInPlace(MatrixBase<Derived> &bAndX) const { ei_assert(m_isInitialized && "LDLT is not initialized."); const Index size = m_matrix.rows(); ei_assert(size == bAndX.rows()); - // z = P b - for(Index i = 0; i < size; ++i) bAndX.row(m_transpositions.coeff(i)).swap(bAndX.row(i)); - - // y = L^-1 z - //matrixL().solveInPlace(bAndX); - m_matrix.template triangularView<UnitLower>().solveInPlace(bAndX); - - // w = D^-1 y - bAndX = m_matrix.diagonal().asDiagonal().inverse() * bAndX; - - // u = L^-T w - m_matrix.adjoint().template triangularView<UnitUpper>().solveInPlace(bAndX); - - // x = P^T u - for (Index i = size-1; i >= 0; --i) bAndX.row(m_transpositions.coeff(i)).swap(bAndX.row(i)); + bAndX = this->solve(bAndX); return true; } @@ -336,24 +390,24 @@ bool LDLT<MatrixType>::solveInPlace(MatrixBase<Derived> &bAndX) const /** \returns the matrix represented by the decomposition, * i.e., it returns the product: P^T L D L^* P. * This function is provided for debug purpose. */ -template<typename MatrixType> -MatrixType LDLT<MatrixType>::reconstructedMatrix() const +template<typename MatrixType, int _UpLo> +MatrixType LDLT<MatrixType,_UpLo>::reconstructedMatrix() const { ei_assert(m_isInitialized && "LDLT is not initialized."); const Index size = m_matrix.rows(); MatrixType res(size,size); - res.setIdentity(); - // PI - for(Index i = 0; i < size; ++i) res.row(m_transpositions.coeff(i)).swap(res.row(i)); + // P + res.setIdentity(); + res = transpositionsP() * res; // L^* P - res = matrixL().adjoint() * res; + res = matrixU() * res; // D(L^*P) res = vectorD().asDiagonal() * res; // L(DL^*P) res = matrixL() * res; // P^T (LDL^*P) - for (Index i = size-1; i >= 0; --i) res.row(m_transpositions.coeff(i)).swap(res.row(i)); + res = transpositionsP().transpose() * res; return res; } @@ -361,6 +415,16 @@ MatrixType LDLT<MatrixType>::reconstructedMatrix() const /** \cholesky_module * \returns the Cholesky decomposition with full pivoting without square root of \c *this */ +template<typename MatrixType, unsigned int UpLo> +inline const LDLT<typename SelfAdjointView<MatrixType, UpLo>::PlainObject, UpLo> +SelfAdjointView<MatrixType, UpLo>::ldlt() const +{ + return LDLT<PlainObject,UpLo>(m_matrix); +} + +/** \cholesky_module + * \returns the Cholesky decomposition with full pivoting without square root of \c *this + */ template<typename Derived> inline const LDLT<typename MatrixBase<Derived>::PlainObject> MatrixBase<Derived>::ldlt() const diff --git a/Eigen/src/Cholesky/LLT.h b/Eigen/src/Cholesky/LLT.h index 29fa465e1..6e7660ddf 100644 --- a/Eigen/src/Cholesky/LLT.h +++ b/Eigen/src/Cholesky/LLT.h @@ -162,7 +162,6 @@ template<typename _MatrixType, int _UpLo> class LLT bool m_isInitialized; }; -// forward declaration (defined at the end of this file) template<int UpLo> struct ei_llt_inplace; template<> struct ei_llt_inplace<Lower> @@ -209,9 +208,12 @@ template<> struct ei_llt_inplace<Lower> for (Index k=0; k<size; k+=blockSize) { + // partition the matrix: + // A00 | - | - + // lu = A10 | A11 | - + // A20 | A21 | A22 Index bs = std::min(blockSize, size-k); Index rs = size - k - bs; - Block<MatrixType,Dynamic,Dynamic> A11(m,k, k, bs,bs); Block<MatrixType,Dynamic,Dynamic> A21(m,k+bs,k, rs,bs); Block<MatrixType,Dynamic,Dynamic> A22(m,k+bs,k+bs,rs,rs); diff --git a/Eigen/src/Core/BandMatrix.h b/Eigen/src/Core/BandMatrix.h index fa0a24762..7ee1eea08 100644 --- a/Eigen/src/Core/BandMatrix.h +++ b/Eigen/src/Core/BandMatrix.h @@ -47,6 +47,7 @@ struct ei_traits<BandMatrix<_Scalar,Rows,Cols,Supers,Subs,Options> > { typedef _Scalar Scalar; typedef Dense StorageKind; + typedef DenseIndex Index; enum { CoeffReadCost = NumTraits<Scalar>::ReadCost, RowsAtCompileTime = Rows, diff --git a/Eigen/src/Core/Block.h b/Eigen/src/Core/Block.h index bb1b8a6b9..59a0f72bc 100644 --- a/Eigen/src/Core/Block.h +++ b/Eigen/src/Core/Block.h @@ -162,7 +162,7 @@ template<typename XprType, int BlockRows, int BlockCols, bool HasDirectAccess> c .coeffRef(row + m_startRow.value(), col + m_startCol.value()); } - inline const CoeffReturnType coeff(Index row, Index col) const + EIGEN_STRONG_INLINE const CoeffReturnType coeff(Index row, Index col) const { return m_xpr.coeff(row + m_startRow.value(), col + m_startCol.value()); } diff --git a/Eigen/src/Core/CwiseBinaryOp.h b/Eigen/src/Core/CwiseBinaryOp.h index 530777577..d0816211a 100644 --- a/Eigen/src/Core/CwiseBinaryOp.h +++ b/Eigen/src/Core/CwiseBinaryOp.h @@ -45,8 +45,19 @@ * \sa MatrixBase::binaryExpr(const MatrixBase<OtherDerived> &,const CustomBinaryOp &) const, class CwiseUnaryOp, class CwiseNullaryOp */ template<typename BinaryOp, typename Lhs, typename Rhs> -struct ei_traits<CwiseBinaryOp<BinaryOp, Lhs, Rhs> > : ei_traits<Lhs> +struct ei_traits<CwiseBinaryOp<BinaryOp, Lhs, Rhs> > { + // we must not inherit from ei_traits<Lhs> since it has + // the potential to cause problems with MSVC + typedef typename ei_cleantype<Lhs>::type Ancestor; + typedef typename ei_traits<Ancestor>::XprKind XprKind; + enum { + RowsAtCompileTime = ei_traits<Ancestor>::RowsAtCompileTime, + ColsAtCompileTime = ei_traits<Ancestor>::ColsAtCompileTime, + MaxRowsAtCompileTime = ei_traits<Ancestor>::MaxRowsAtCompileTime, + MaxColsAtCompileTime = ei_traits<Ancestor>::MaxColsAtCompileTime + }; + // even though we require Lhs and Rhs to have the same scalar type (see CwiseBinaryOp constructor), // we still want to handle the case when the result type is different. typedef typename ei_result_of< @@ -57,6 +68,8 @@ struct ei_traits<CwiseBinaryOp<BinaryOp, Lhs, Rhs> > : ei_traits<Lhs> >::type Scalar; typedef typename ei_promote_storage_type<typename ei_traits<Lhs>::StorageKind, typename ei_traits<Rhs>::StorageKind>::ret StorageKind; + typedef typename ei_promote_index_type<typename ei_traits<Lhs>::Index, + typename ei_traits<Rhs>::Index>::type Index; typedef typename Lhs::Nested LhsNested; typedef typename Rhs::Nested RhsNested; typedef typename ei_unref<LhsNested>::type _LhsNested; @@ -97,7 +110,7 @@ class CwiseBinaryOp : ei_no_assignment_operator, BinaryOp, Lhs, Rhs, typename ei_promote_storage_type<typename ei_traits<Lhs>::StorageKind, typename ei_traits<Rhs>::StorageKind>::ret>::Base Base; - EIGEN_GENERIC_PUBLIC_INTERFACE_NEW(CwiseBinaryOp) + EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseBinaryOp) typedef typename ei_nested<Lhs>::type LhsNested; typedef typename ei_nested<Rhs>::type RhsNested; @@ -125,14 +138,14 @@ class CwiseBinaryOp : ei_no_assignment_operator, EIGEN_STRONG_INLINE Index rows() const { // return the fixed size type if available to enable compile time optimizations - if (ei_traits<typename ei_cleantype<LhsNested>::type>::RowsAtCompileTime==Dynamic) + if (ei_traits<typename ei_cleantype<LhsNested>::type>::RowsAtCompileTime==Dynamic) return m_rhs.rows(); else return m_lhs.rows(); } EIGEN_STRONG_INLINE Index cols() const { // return the fixed size type if available to enable compile time optimizations - if (ei_traits<typename ei_cleantype<LhsNested>::type>::ColsAtCompileTime==Dynamic) + if (ei_traits<typename ei_cleantype<LhsNested>::type>::ColsAtCompileTime==Dynamic) return m_rhs.cols(); else return m_lhs.cols(); diff --git a/Eigen/src/Core/CwiseUnaryOp.h b/Eigen/src/Core/CwiseUnaryOp.h index da398d131..a05ef1d9f 100644 --- a/Eigen/src/Core/CwiseUnaryOp.h +++ b/Eigen/src/Core/CwiseUnaryOp.h @@ -71,7 +71,7 @@ class CwiseUnaryOp : ei_no_assignment_operator, public: typedef typename CwiseUnaryOpImpl<UnaryOp, XprType,typename ei_traits<XprType>::StorageKind>::Base Base; - EIGEN_GENERIC_PUBLIC_INTERFACE_NEW(CwiseUnaryOp) + EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryOp) inline CwiseUnaryOp(const XprType& xpr, const UnaryOp& func = UnaryOp()) : m_xpr(xpr), m_functor(func) {} diff --git a/Eigen/src/Core/CwiseUnaryView.h b/Eigen/src/Core/CwiseUnaryView.h index 953fc89a6..f89088072 100644 --- a/Eigen/src/Core/CwiseUnaryView.h +++ b/Eigen/src/Core/CwiseUnaryView.h @@ -70,7 +70,7 @@ class CwiseUnaryView : ei_no_assignment_operator, public: typedef typename CwiseUnaryViewImpl<ViewOp, MatrixType,typename ei_traits<MatrixType>::StorageKind>::Base Base; - EIGEN_GENERIC_PUBLIC_INTERFACE_NEW(CwiseUnaryView) + EIGEN_GENERIC_PUBLIC_INTERFACE(CwiseUnaryView) inline CwiseUnaryView(const MatrixType& mat, const ViewOp& func = ViewOp()) : m_matrix(mat), m_functor(func) {} diff --git a/Eigen/src/Core/DenseBase.h b/Eigen/src/Core/DenseBase.h index c4b4057a4..95e37801d 100644 --- a/Eigen/src/Core/DenseBase.h +++ b/Eigen/src/Core/DenseBase.h @@ -51,7 +51,7 @@ template<typename Derived> class DenseBase class InnerIterator; typedef typename ei_traits<Derived>::StorageKind StorageKind; - typedef typename ei_index<StorageKind>::type Index; + typedef typename ei_traits<Derived>::Index Index; typedef typename ei_traits<Derived>::Scalar Scalar; typedef typename ei_packet_traits<Scalar>::type PacketScalar; typedef typename NumTraits<Scalar>::Real RealScalar; @@ -218,8 +218,8 @@ template<typename Derived> class DenseBase */ void resize(Index rows, Index cols) { - EIGEN_ONLY_USED_FOR_DEBUG(rows); - EIGEN_ONLY_USED_FOR_DEBUG(cols); + EIGEN_ONLY_USED_FOR_DEBUG(rows); + EIGEN_ONLY_USED_FOR_DEBUG(cols); ei_assert(rows == this->rows() && cols == this->cols() && "DenseBase::resize() does not actually allow to resize."); } @@ -247,7 +247,7 @@ template<typename Derived> class DenseBase /** \internal expression type of a block of whole rows */ template<int N> struct NRowsBlockXpr { typedef Block<Derived, N, ei_traits<Derived>::ColsAtCompileTime> Type; }; - + #endif // not EIGEN_PARSED_BY_DOXYGEN /** Copies \a other into *this. \returns a reference to *this. */ @@ -440,8 +440,8 @@ template<typename Derived> class DenseBase * a const reference, in order to avoid a useless copy. */ EIGEN_STRONG_INLINE const typename ei_eval<Derived>::type eval() const - { - // Even though MSVC does not honor strong inlining when the return type + { + // Even though MSVC does not honor strong inlining when the return type // is a dynamic matrix, we desperately need strong inlining for fixed // size types on MSVC. return typename ei_eval<Derived>::type(derived()); diff --git a/Eigen/src/Core/DenseCoeffsBase.h b/Eigen/src/Core/DenseCoeffsBase.h index 7026bbe34..c55576c02 100644 --- a/Eigen/src/Core/DenseCoeffsBase.h +++ b/Eigen/src/Core/DenseCoeffsBase.h @@ -30,7 +30,7 @@ class DenseCoeffsBase : public EigenBase<Derived> { public: typedef typename ei_traits<Derived>::StorageKind StorageKind; - typedef typename ei_index<StorageKind>::type Index; + typedef typename ei_traits<Derived>::Index Index; typedef typename ei_traits<Derived>::Scalar Scalar; typedef typename ei_packet_traits<Scalar>::type PacketScalar; typedef typename ei_meta_if<ei_has_direct_access<Derived>::ret, const Scalar&, Scalar>::ret CoeffReturnType; @@ -40,7 +40,7 @@ class DenseCoeffsBase : public EigenBase<Derived> using Base::cols; using Base::size; using Base::derived; - + EIGEN_STRONG_INLINE Index rowIndexByOuterInner(Index outer, Index inner) const { return int(Derived::RowsAtCompileTime) == 1 ? 0 @@ -245,7 +245,7 @@ class DenseCoeffsBase<Derived, true> : public DenseCoeffsBase<Derived, false> typedef DenseCoeffsBase<Derived, false> Base; typedef typename ei_traits<Derived>::StorageKind StorageKind; - typedef typename ei_index<StorageKind>::type Index; + typedef typename ei_traits<Derived>::Index Index; typedef typename ei_traits<Derived>::Scalar Scalar; typedef typename ei_packet_traits<Scalar>::type PacketScalar; typedef typename NumTraits<Scalar>::Real RealScalar; diff --git a/Eigen/src/Core/DenseStorageBase.h b/Eigen/src/Core/DenseStorageBase.h index 6df7e4b18..2bdb12b78 100644 --- a/Eigen/src/Core/DenseStorageBase.h +++ b/Eigen/src/Core/DenseStorageBase.h @@ -46,7 +46,7 @@ class DenseStorageBase : public ei_dense_xpr_base<Derived>::type typedef typename ei_dense_xpr_base<Derived>::type Base; typedef typename ei_traits<Derived>::StorageKind StorageKind; - typedef typename ei_index<StorageKind>::type Index; + typedef typename ei_traits<Derived>::Index Index; typedef typename ei_traits<Derived>::Scalar Scalar; typedef typename ei_packet_traits<Scalar>::type PacketScalar; typedef typename NumTraits<Scalar>::Real RealScalar; @@ -159,7 +159,7 @@ class DenseStorageBase : public ei_dense_xpr_base<Derived>::type * * \sa resize(Index) for vectors, resize(NoChange_t, Index), resize(Index, NoChange_t) */ - inline void resize(Index rows, Index cols) + EIGEN_STRONG_INLINE void resize(Index rows, Index cols) { #ifdef EIGEN_INITIALIZE_MATRICES_BY_ZERO Index size = rows*cols; @@ -471,7 +471,9 @@ class DenseStorageBase : public ei_dense_xpr_base<Derived>::type template<typename OtherDerived> EIGEN_STRONG_INLINE Derived& _set_noalias(const DenseBase<OtherDerived>& other) { - _resize_to_match(other); + // I don't think we need this resize call since the lazyAssign will anyways resize + // and lazyAssign will be called by the assign selector. + //_resize_to_match(other); // the 'false' below means to enforce lazy evaluation. We don't use lazyAssign() because // it wouldn't allow to copy a row-vector into a column-vector. return ei_assign_selector<Derived,OtherDerived,false>::run(this->derived(), other.derived()); diff --git a/Eigen/src/Core/DiagonalMatrix.h b/Eigen/src/Core/DiagonalMatrix.h index 8d3b458a9..34eeda089 100644 --- a/Eigen/src/Core/DiagonalMatrix.h +++ b/Eigen/src/Core/DiagonalMatrix.h @@ -34,7 +34,7 @@ class DiagonalBase : public EigenBase<Derived> typedef typename ei_traits<Derived>::DiagonalVectorType DiagonalVectorType; typedef typename DiagonalVectorType::Scalar Scalar; typedef typename ei_traits<Derived>::StorageKind StorageKind; - typedef typename ei_index<StorageKind>::type Index; + typedef typename ei_traits<Derived>::Index Index; enum { RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, @@ -103,6 +103,7 @@ struct ei_traits<DiagonalMatrix<_Scalar,SizeAtCompileTime,MaxSizeAtCompileTime> { typedef Matrix<_Scalar,SizeAtCompileTime,1,0,MaxSizeAtCompileTime,1> DiagonalVectorType; typedef Dense StorageKind; + typedef DenseIndex Index; }; template<typename _Scalar, int SizeAtCompileTime, int MaxSizeAtCompileTime> @@ -115,7 +116,7 @@ class DiagonalMatrix typedef const DiagonalMatrix& Nested; typedef _Scalar Scalar; typedef typename ei_traits<DiagonalMatrix>::StorageKind StorageKind; - typedef typename ei_index<StorageKind>::type Index; + typedef typename ei_traits<DiagonalMatrix>::Index Index; #endif protected: @@ -203,6 +204,7 @@ struct ei_traits<DiagonalWrapper<_DiagonalVectorType> > { typedef _DiagonalVectorType DiagonalVectorType; typedef typename DiagonalVectorType::Scalar Scalar; + typedef typename DiagonalVectorType::Index Index; typedef typename DiagonalVectorType::StorageKind StorageKind; enum { RowsAtCompileTime = DiagonalVectorType::SizeAtCompileTime, diff --git a/Eigen/src/Core/Dot.h b/Eigen/src/Core/Dot.h index 6e54dac3c..dfa313e89 100644 --- a/Eigen/src/Core/Dot.h +++ b/Eigen/src/Core/Dot.h @@ -85,7 +85,7 @@ MatrixBase<Derived>::dot(const MatrixBase<OtherDerived>& other) const * \sa dot(), norm() */ template<typename Derived> -inline typename NumTraits<typename ei_traits<Derived>::Scalar>::Real MatrixBase<Derived>::squaredNorm() const +EIGEN_STRONG_INLINE typename NumTraits<typename ei_traits<Derived>::Scalar>::Real MatrixBase<Derived>::squaredNorm() const { return ei_real((*this).cwiseAbs2().sum()); } diff --git a/Eigen/src/Core/EigenBase.h b/Eigen/src/Core/EigenBase.h index c9d3bd875..3485b36d2 100644 --- a/Eigen/src/Core/EigenBase.h +++ b/Eigen/src/Core/EigenBase.h @@ -40,7 +40,7 @@ template<typename Derived> struct EigenBase // typedef typename ei_plain_matrix_type<Derived>::type PlainObject; typedef typename ei_traits<Derived>::StorageKind StorageKind; - typedef typename ei_index<StorageKind>::type Index; + typedef typename ei_traits<Derived>::Index Index; /** \returns a reference to the derived object */ Derived& derived() { return *static_cast<Derived*>(this); } diff --git a/Eigen/src/Core/MapBase.h b/Eigen/src/Core/MapBase.h index 979eef707..a08de30d3 100644 --- a/Eigen/src/Core/MapBase.h +++ b/Eigen/src/Core/MapBase.h @@ -46,7 +46,7 @@ template<typename Derived> class MapBase typedef typename ei_traits<Derived>::StorageKind StorageKind; - typedef typename ei_index<StorageKind>::type Index; + typedef typename ei_traits<Derived>::Index Index; typedef typename ei_traits<Derived>::Scalar Scalar; typedef typename ei_packet_traits<Scalar>::type PacketScalar; typedef typename NumTraits<Scalar>::Real RealScalar; diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index 4407b0db1..54fca7046 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -113,6 +113,7 @@ struct ei_traits<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> > { typedef _Scalar Scalar; typedef Dense StorageKind; + typedef DenseIndex Index; typedef MatrixXpr XprKind; enum { RowsAtCompileTime = _Rows, diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 0a81c4da0..cc35800bf 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -58,11 +58,11 @@ template<typename Derived> class MatrixBase #ifndef EIGEN_PARSED_BY_DOXYGEN typedef MatrixBase StorageBaseType; typedef typename ei_traits<Derived>::StorageKind StorageKind; - typedef typename ei_index<StorageKind>::type Index; + typedef typename ei_traits<Derived>::Index Index; typedef typename ei_traits<Derived>::Scalar Scalar; typedef typename ei_packet_traits<Scalar>::type PacketScalar; typedef typename NumTraits<Scalar>::Real RealScalar; - + typedef DenseBase<Derived> Base; using Base::RowsAtCompileTime; using Base::ColsAtCompileTime; diff --git a/Eigen/src/Core/MatrixStorage.h b/Eigen/src/Core/MatrixStorage.h index aff83a64c..0165966f4 100644 --- a/Eigen/src/Core/MatrixStorage.h +++ b/Eigen/src/Core/MatrixStorage.h @@ -243,7 +243,7 @@ template<typename T, int _Rows, int _Options> class ei_matrix_storage<T, Dynamic m_data = ei_conditional_aligned_realloc_new<T,(_Options&DontAlign)==0>(m_data, size, _Rows*m_cols); m_cols = cols; } - void resize(DenseIndex size, DenseIndex, DenseIndex cols) + EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex, DenseIndex cols) { if(size != _Rows*m_cols) { @@ -279,7 +279,7 @@ template<typename T, int _Cols, int _Options> class ei_matrix_storage<T, Dynamic m_data = ei_conditional_aligned_realloc_new<T,(_Options&DontAlign)==0>(m_data, size, m_rows*_Cols); m_rows = rows; } - void resize(DenseIndex size, DenseIndex rows, DenseIndex) + EIGEN_STRONG_INLINE void resize(DenseIndex size, DenseIndex rows, DenseIndex) { if(size != m_rows*_Cols) { diff --git a/Eigen/src/Core/NoAlias.h b/Eigen/src/Core/NoAlias.h index 0542571e2..30ddbeb3c 100644 --- a/Eigen/src/Core/NoAlias.h +++ b/Eigen/src/Core/NoAlias.h @@ -45,18 +45,12 @@ class NoAlias public: NoAlias(ExpressionType& expression) : m_expression(expression) {} - /* \sa MatrixBase::lazyAssign() */ + /** Behaves like MatrixBase::lazyAssign(other) + * \sa MatrixBase::lazyAssign() */ template<typename OtherDerived> EIGEN_STRONG_INLINE ExpressionType& operator=(const StorageBase<OtherDerived>& other) { return m_expression.lazyAssign(other.derived()); } - template<typename OtherDerived> - EIGEN_STRONG_INLINE ExpressionType& operator=(const ReturnByValue<OtherDerived>& other) - { - other.evalTo(m_expression); - return m_expression; - } - /** \sa MatrixBase::operator+= */ template<typename OtherDerived> EIGEN_STRONG_INLINE ExpressionType& operator+=(const StorageBase<OtherDerived>& other) diff --git a/Eigen/src/Core/PermutationMatrix.h b/Eigen/src/Core/PermutationMatrix.h index 46884dc3f..8227c9bf9 100644 --- a/Eigen/src/Core/PermutationMatrix.h +++ b/Eigen/src/Core/PermutationMatrix.h @@ -2,6 +2,7 @@ // for linear algebra. // // Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com> +// Copyright (C) 2009 Gael Guennebaud <g.gael@free.fr> // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -46,7 +47,6 @@ * * \sa class DiagonalMatrix */ -template<int SizeAtCompileTime, int MaxSizeAtCompileTime = SizeAtCompileTime> class PermutationMatrix; template<typename PermutationType, typename MatrixType, int Side, bool Transposed=false> struct ei_permut_matrix_product_retval; template<int SizeAtCompileTime, int MaxSizeAtCompileTime> @@ -77,8 +77,12 @@ class PermutationMatrix : public EigenBase<PermutationMatrix<SizeAtCompileTime, typedef Matrix<int, SizeAtCompileTime, 1, 0, MaxSizeAtCompileTime, 1> IndicesType; inline PermutationMatrix() - { - } + {} + + /** Constructs an uninitialized permutation matrix of given size. + */ + inline PermutationMatrix(int size) : m_indices(size) + {} /** Copy constructor. */ template<int OtherSize, int OtherMaxSize> @@ -102,6 +106,14 @@ class PermutationMatrix : public EigenBase<PermutationMatrix<SizeAtCompileTime, explicit inline PermutationMatrix(const MatrixBase<Other>& indices) : m_indices(indices) {} + /** Convert the Transpositions \a tr to a permutation matrix */ + template<int OtherSize, int OtherMaxSize> + explicit PermutationMatrix(const Transpositions<OtherSize,OtherMaxSize>& tr) + : m_indices(tr.size()) + { + *this = tr; + } + /** Copies the other permutation into *this */ template<int OtherSize, int OtherMaxSize> PermutationMatrix& operator=(const PermutationMatrix<OtherSize, OtherMaxSize>& other) @@ -110,6 +122,16 @@ class PermutationMatrix : public EigenBase<PermutationMatrix<SizeAtCompileTime, return *this; } + /** Assignment from the Transpositions \a tr */ + template<int OtherSize, int OtherMaxSize> + PermutationMatrix& operator=(const Transpositions<OtherSize,OtherMaxSize>& tr) + { + setIdentity(tr.size()); + for(int k=size()-1; k>=0; --k) + applyTranspositionOnTheRight(k,tr.coeff(k)); + return *this; + } + #ifndef EIGEN_PARSED_BY_DOXYGEN /** This is a special case of the templated operator=. Its purpose is to * prevent a default operator= from hiding the templated operator=. @@ -121,11 +143,6 @@ class PermutationMatrix : public EigenBase<PermutationMatrix<SizeAtCompileTime, } #endif - /** Constructs an uninitialized permutation matrix of given size. - */ - inline PermutationMatrix(int size) : m_indices(size) - {} - /** \returns the number of rows */ inline int rows() const { return m_indices.size(); } diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index b9aab524b..753f6b4b5 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -194,6 +194,11 @@ class GeneralProduct<Lhs, Rhs, InnerProduct> } typename Base::Scalar value() const { return Base::coeff(0,0); } + + /** Convertion to scalar */ + operator const typename Base::Scalar() const { + return Base::coeff(0,0); + } }; /*********************************************************************** diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index 36626f838..35a3a280f 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -37,6 +37,8 @@ struct ei_traits<ProductBase<Derived,_Lhs,_Rhs> > typedef typename ei_scalar_product_traits<typename Lhs::Scalar, typename Rhs::Scalar>::ReturnType Scalar; typedef typename ei_promote_storage_type<typename ei_traits<Lhs>::StorageKind, typename ei_traits<Rhs>::StorageKind>::ret StorageKind; + typedef typename ei_promote_index_type<typename ei_traits<Lhs>::Index, + typename ei_traits<Rhs>::Index>::type Index; enum { RowsAtCompileTime = ei_traits<Lhs>::RowsAtCompileTime, ColsAtCompileTime = ei_traits<Rhs>::ColsAtCompileTime, diff --git a/Eigen/src/Core/Redux.h b/Eigen/src/Core/Redux.h index b3e60192f..cfbaa0986 100644 --- a/Eigen/src/Core/Redux.h +++ b/Eigen/src/Core/Redux.h @@ -181,7 +181,7 @@ struct ei_redux_impl<Func, Derived, DefaultTraversal, NoUnrolling> { typedef typename Derived::Scalar Scalar; typedef typename Derived::Index Index; - static Scalar run(const Derived& mat, const Func& func) + static EIGEN_STRONG_INLINE Scalar run(const Derived& mat, const Func& func) { ei_assert(mat.rows()>0 && mat.cols()>0 && "you are using a non initialized matrix"); Scalar res; @@ -311,7 +311,7 @@ struct ei_redux_impl<Func, Derived, LinearVectorizedTraversal, CompleteUnrolling */ template<typename Derived> template<typename Func> -inline typename ei_result_of<Func(typename ei_traits<Derived>::Scalar)>::type +EIGEN_STRONG_INLINE typename ei_result_of<Func(typename ei_traits<Derived>::Scalar)>::type DenseBase<Derived>::redux(const Func& func) const { typedef typename ei_cleantype<typename Derived::Nested>::type ThisNested; diff --git a/Eigen/src/Core/ReturnByValue.h b/Eigen/src/Core/ReturnByValue.h index 665d48031..90887356c 100644 --- a/Eigen/src/Core/ReturnByValue.h +++ b/Eigen/src/Core/ReturnByValue.h @@ -36,9 +36,9 @@ struct ei_traits<ReturnByValue<Derived> > enum { // We're disabling the DirectAccess because e.g. the constructor of // the Block-with-DirectAccess expression requires to have a coeffRef method. - // FIXME this should be fixed so we can have DirectAccessBit here. + // Also, we don't want to have to implement the stride stuff. Flags = (ei_traits<typename ei_traits<Derived>::ReturnType>::Flags - | EvalBeforeNestingBit | EvalBeforeAssigningBit) & ~DirectAccessBit + | EvalBeforeNestingBit) & ~DirectAccessBit }; }; @@ -84,11 +84,8 @@ template<typename Derived> template<typename OtherDerived> Derived& DenseBase<Derived>::operator=(const ReturnByValue<OtherDerived>& other) { - // since we're by-passing the mechanisms in Assign.h, we implement here the EvalBeforeAssigningBit. - // override by using .noalias(), see corresponding operator= in NoAlias. - typename Derived::PlainObject result(rows(), cols()); - other.evalTo(result); - return (derived() = result); + other.evalTo(derived()); + return derived(); } #endif // EIGEN_RETURNBYVALUE_H diff --git a/Eigen/src/Core/SelfAdjointView.h b/Eigen/src/Core/SelfAdjointView.h index eed3f9336..84c4dc521 100644 --- a/Eigen/src/Core/SelfAdjointView.h +++ b/Eigen/src/Core/SelfAdjointView.h @@ -153,7 +153,7 @@ template<typename MatrixType, unsigned int UpLo> class SelfAdjointView /////////// Cholesky module /////////// const LLT<PlainObject, UpLo> llt() const; - const LDLT<PlainObject> ldlt() const; + const LDLT<PlainObject, UpLo> ldlt() const; /////////// Eigenvalue module /////////// diff --git a/Eigen/src/Core/StableNorm.h b/Eigen/src/Core/StableNorm.h index d2bed929b..e3eab4bd8 100644 --- a/Eigen/src/Core/StableNorm.h +++ b/Eigen/src/Core/StableNorm.h @@ -87,7 +87,7 @@ MatrixBase<Derived>::blueNorm() const static RealScalar b1, b2, s1m, s2m, overfl, rbig, relerr; if(nmax <= 0) { - Index nbig, ibeta, it, iemin, iemax, iexp; + int nbig, ibeta, it, iemin, iemax, iexp; RealScalar abig, eps; // This program calculates the machine-dependent constants // bl, b2, slm, s2m, relerr overfl, nmax diff --git a/Eigen/src/Core/Transpose.h b/Eigen/src/Core/Transpose.h index 38d942e04..6928ae31a 100644 --- a/Eigen/src/Core/Transpose.h +++ b/Eigen/src/Core/Transpose.h @@ -66,7 +66,7 @@ template<typename MatrixType> class Transpose public: typedef typename TransposeImpl<MatrixType,typename ei_traits<MatrixType>::StorageKind>::Base Base; - EIGEN_GENERIC_PUBLIC_INTERFACE_NEW(Transpose) + EIGEN_GENERIC_PUBLIC_INTERFACE(Transpose) inline Transpose(const MatrixType& matrix) : m_matrix(matrix) {} diff --git a/Eigen/src/Core/Transpositions.h b/Eigen/src/Core/Transpositions.h new file mode 100644 index 000000000..b71d46aa6 --- /dev/null +++ b/Eigen/src/Core/Transpositions.h @@ -0,0 +1,292 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2010 Gael Guennebaud <g.gael@free.fr> +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see <http://www.gnu.org/licenses/>. + +#ifndef EIGEN_TRANSPOSITIONS_H +#define EIGEN_TRANSPOSITIONS_H + +/** \class Transpositions + * + * \brief Represents a sequence of transpositions (row/column interchange) + * + * \param SizeAtCompileTime the number of transpositions, or Dynamic + * \param MaxSizeAtCompileTime the maximum number of transpositions, or Dynamic. This optional parameter defaults to SizeAtCompileTime. Most of the time, you should not have to specify it. + * + * This class represents a permutation transformation as a sequence of \em n transpositions + * \f$[T_{n-1} \ldots T_{i} \ldots T_{0}]\f$. It is internally stored as a vector of integers \c indices. + * Each transposition \f$ T_{i} \f$ applied on the left of a matrix (\f$ T_{i} M\f$) interchanges + * the rows \c i and \c indices[i] of the matrix \c M. + * A transposition applied on the right (e.g., \f$ M T_{i}\f$) yields a column interchange. + * + * Compared to the class PermutationMatrix, such a sequence of transpositions is what is + * computed during a decomposition with pivoting, and it is faster when applying the permutation in-place. + * + * To apply a sequence of transpositions to a matrix, simply use the operator * as in the following example: + * \code + * Transpositions tr; + * MatrixXf mat; + * mat = tr * mat; + * \endcode + * In this example, we detect that the matrix appears on both side, and so the transpositions + * are applied in-place without any temporary or extra copy. + * + * \sa class PermutationMatrix + */ +template<typename TranspositionType, typename MatrixType, int Side, bool Transposed=false> struct ei_transposition_matrix_product_retval; + +template<int SizeAtCompileTime, int MaxSizeAtCompileTime> +class Transpositions +{ + public: + + typedef Matrix<DenseIndex, SizeAtCompileTime, 1, 0, MaxSizeAtCompileTime, 1> IndicesType; + typedef typename IndicesType::Index Index; + + inline Transpositions() {} + + /** Copy constructor. */ + template<int OtherSize, int OtherMaxSize> + inline Transpositions(const Transpositions<OtherSize, OtherMaxSize>& other) + : m_indices(other.indices()) {} + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** Standard copy constructor. Defined only to prevent a default copy constructor + * from hiding the other templated constructor */ + inline Transpositions(const Transpositions& other) : m_indices(other.indices()) {} + #endif + + /** Generic constructor from expression of the transposition indices. */ + template<typename Other> + explicit inline Transpositions(const MatrixBase<Other>& indices) : m_indices(indices) + {} + + /** Copies the \a other transpositions into \c *this */ + template<int OtherSize, int OtherMaxSize> + Transpositions& operator=(const Transpositions<OtherSize, OtherMaxSize>& other) + { + m_indices = other.indices(); + return *this; + } + + #ifndef EIGEN_PARSED_BY_DOXYGEN + /** This is a special case of the templated operator=. Its purpose is to + * prevent a default operator= from hiding the templated operator=. + */ + Transpositions& operator=(const Transpositions& other) + { + m_indices = other.m_indices; + return *this; + } + #endif + + /** Constructs an uninitialized permutation matrix of given size. + */ + inline Transpositions(Index size) : m_indices(size) + {} + + /** \returns the number of transpositions */ + inline Index size() const { return m_indices.size(); } + + /** Direct access to the underlying index vector */ + inline const Index& coeff(Index i) const { return m_indices.coeff(i); } + /** Direct access to the underlying index vector */ + inline Index& coeffRef(Index i) { return m_indices.coeffRef(i); } + /** Direct access to the underlying index vector */ + inline const Index& operator()(Index i) const { return m_indices(i); } + /** Direct access to the underlying index vector */ + inline Index& operator()(Index i) { return m_indices(i); } + /** Direct access to the underlying index vector */ + inline const Index& operator[](Index i) const { return m_indices(i); } + /** Direct access to the underlying index vector */ + inline Index& operator[](Index i) { return m_indices(i); } + + /** const version of indices(). */ + const IndicesType& indices() const { return m_indices; } + /** \returns a reference to the stored array representing the transpositions. */ + IndicesType& indices() { return m_indices; } + + /** Resizes to given size. */ + inline void resize(int size) + { + m_indices.resize(size); + } + + /** Sets \c *this to represents an identity transformation */ + void setIdentity() + { + for(int i = 0; i < m_indices.size(); ++i) + m_indices.coeffRef(i) = i; + } + + // FIXME: do we want such methods ? + // might be usefull when the target matrix expression is complex, e.g.: + // object.matrix().block(..,..,..,..) = trans * object.matrix().block(..,..,..,..); + /* + template<typename MatrixType> + void applyForwardToRows(MatrixType& mat) const + { + for(Index k=0 ; k<size() ; ++k) + if(m_indices(k)!=k) + mat.row(k).swap(mat.row(m_indices(k))); + } + + template<typename MatrixType> + void applyBackwardToRows(MatrixType& mat) const + { + for(Index k=size()-1 ; k>=0 ; --k) + if(m_indices(k)!=k) + mat.row(k).swap(mat.row(m_indices(k))); + } + */ + + /** \returns the inverse transformation */ + inline Transpose<Transpositions> inverse() const + { return *this; } + + /** \returns the tranpose transformation */ + inline Transpose<Transpositions> transpose() const + { return *this; } + +#ifndef EIGEN_PARSED_BY_DOXYGEN + template<int OtherSize, int OtherMaxSize> + Transpositions(const Transpose<Transpositions<OtherSize,OtherMaxSize> >& other) + : m_indices(other.size()) + { + Index n = size(); + Index j = size-1; + for(Index i=0; i<n;++i,--j) + m_indices.coeffRef(j) = other.nestedTranspositions().indices().coeff(i); + } +#endif + + protected: + + IndicesType m_indices; +}; + +/** \returns the \a matrix with the \a transpositions applied to the columns. + */ +template<typename Derived, int SizeAtCompileTime, int MaxSizeAtCompileTime> +inline const ei_transposition_matrix_product_retval<Transpositions<SizeAtCompileTime, MaxSizeAtCompileTime>, Derived, OnTheRight> +operator*(const MatrixBase<Derived>& matrix, + const Transpositions<SizeAtCompileTime, MaxSizeAtCompileTime> &transpositions) +{ + return ei_transposition_matrix_product_retval + <Transpositions<SizeAtCompileTime, MaxSizeAtCompileTime>, Derived, OnTheRight> + (transpositions, matrix.derived()); +} + +/** \returns the \a matrix with the \a transpositions applied to the rows. + */ +template<typename Derived, int SizeAtCompileTime, int MaxSizeAtCompileTime> +inline const ei_transposition_matrix_product_retval + <Transpositions<SizeAtCompileTime, MaxSizeAtCompileTime>, Derived, OnTheLeft> +operator*(const Transpositions<SizeAtCompileTime, MaxSizeAtCompileTime> &transpositions, + const MatrixBase<Derived>& matrix) +{ + return ei_transposition_matrix_product_retval + <Transpositions<SizeAtCompileTime, MaxSizeAtCompileTime>, Derived, OnTheLeft> + (transpositions, matrix.derived()); +} + +template<typename TranspositionType, typename MatrixType, int Side, bool Transposed> +struct ei_traits<ei_transposition_matrix_product_retval<TranspositionType, MatrixType, Side, Transposed> > +{ + typedef typename MatrixType::PlainObject ReturnType; +}; + +template<typename TranspositionType, typename MatrixType, int Side, bool Transposed> +struct ei_transposition_matrix_product_retval + : public ReturnByValue<ei_transposition_matrix_product_retval<TranspositionType, MatrixType, Side, Transposed> > +{ + typedef typename ei_cleantype<typename MatrixType::Nested>::type MatrixTypeNestedCleaned; + typedef typename TranspositionType::Index Index; + + ei_transposition_matrix_product_retval(const TranspositionType& tr, const MatrixType& matrix) + : m_transpositions(tr), m_matrix(matrix) + {} + + inline int rows() const { return m_matrix.rows(); } + inline int cols() const { return m_matrix.cols(); } + + template<typename Dest> inline void evalTo(Dest& dst) const + { + const int size = m_transpositions.size(); + Index j = 0; + + if(!(ei_is_same_type<MatrixTypeNestedCleaned,Dest>::ret && ei_extract_data(dst) == ei_extract_data(m_matrix))) + dst = m_matrix; + + for(int k=(Transposed?size-1:0) ; Transposed?k>=0:k<size ; Transposed?--k:++k) + if((j=m_transpositions.coeff(k))!=k) + { + if(Side==OnTheLeft) + dst.row(k).swap(dst.row(j)); + else if(Side==OnTheRight) + dst.col(k).swap(dst.col(j)); + } + } + + protected: + const TranspositionType& m_transpositions; + const typename MatrixType::Nested m_matrix; +}; + +/* Template partial specialization for transposed/inverse transpositions */ + +template<int SizeAtCompileTime, int MaxSizeAtCompileTime> +class Transpose<Transpositions<SizeAtCompileTime, MaxSizeAtCompileTime> > +{ + typedef Transpositions<SizeAtCompileTime, MaxSizeAtCompileTime> TranspositionType; + typedef typename TranspositionType::IndicesType IndicesType; + public: + + Transpose(const TranspositionType& t) : m_transpositions(t) {} + + inline int size() const { return m_transpositions.size(); } + + /** \returns the \a matrix with the inverse transpositions applied to the columns. + */ + template<typename Derived> friend + inline const ei_transposition_matrix_product_retval<TranspositionType, Derived, OnTheRight, true> + operator*(const MatrixBase<Derived>& matrix, const Transpose& trt) + { + return ei_transposition_matrix_product_retval<TranspositionType, Derived, OnTheRight, true>(trt.m_transpositions, matrix.derived()); + } + + /** \returns the \a matrix with the inverse transpositions applied to the rows. + */ + template<typename Derived> + inline const ei_transposition_matrix_product_retval<TranspositionType, Derived, OnTheLeft, true> + operator*(const MatrixBase<Derived>& matrix) const + { + return ei_transposition_matrix_product_retval<TranspositionType, Derived, OnTheLeft, true>(m_transpositions, matrix.derived()); + } + + const TranspositionType& nestedTranspositions() const { return m_transpositions; } + + protected: + const TranspositionType& m_transpositions; +}; + +#endif // EIGEN_TRANSPOSITIONS_H diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 03347b09c..1f5739c3c 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -46,7 +46,7 @@ template<typename Derived> class TriangularBase : public EigenBase<Derived> }; typedef typename ei_traits<Derived>::Scalar Scalar; typedef typename ei_traits<Derived>::StorageKind StorageKind; - typedef typename ei_index<StorageKind>::type Index; + typedef typename ei_traits<Derived>::Index Index; inline TriangularBase() { ei_assert(!((Mode&UnitDiag) && (Mode&ZeroDiag))); } @@ -156,10 +156,10 @@ template<typename _MatrixType, unsigned int _Mode> class TriangularView typedef typename MatrixType::PlainObject DenseMatrixType; typedef typename MatrixType::Nested MatrixTypeNested; typedef typename ei_cleantype<MatrixTypeNested>::type _MatrixTypeNested; - using TriangularBase<TriangularView<_MatrixType, _Mode> >::evalToLazy; + using Base::evalToLazy; typedef typename ei_traits<TriangularView>::StorageKind StorageKind; - typedef typename ei_index<StorageKind>::type Index; + typedef typename ei_traits<TriangularView>::Index Index; enum { Mode = _Mode, diff --git a/Eigen/src/Core/arch/AltiVec/PacketMath.h b/Eigen/src/Core/arch/AltiVec/PacketMath.h index 0a7b07645..2feca365a 100644 --- a/Eigen/src/Core/arch/AltiVec/PacketMath.h +++ b/Eigen/src/Core/arch/AltiVec/PacketMath.h @@ -31,10 +31,10 @@ #ifndef EIGEN_HAS_FUSE_CJMADD #define EIGEN_HAS_FUSE_CJMADD 1 -#endif +#endif #ifndef EIGEN_TUNE_FOR_CPU_CACHE_SIZE -#define EIGEN_TUNE_FOR_CPU_CACHE_SIZE 8*128*128 +#define EIGEN_TUNE_FOR_CPU_CACHE_SIZE 8*256*256 #endif // NOTE Altivec has 32 registers, but Eigen only accepts a value of 8 or 16 @@ -153,7 +153,7 @@ template<> EIGEN_STRONG_INLINE Packet4f ei_pset1<float>(const float& from) { return vc; } -template<> EIGEN_STRONG_INLINE Packet4i ei_pset1<int>(const int& from) { +template<> EIGEN_STRONG_INLINE Packet4i ei_pset1<int>(const int& from) { int EIGEN_ALIGN16 ai[4]; ai[0] = from; Packet4i vc = vec_ld(0, ai); diff --git a/Eigen/src/Core/arch/Default/Settings.h b/Eigen/src/Core/arch/Default/Settings.h index 1ab2877b6..150c4bdc7 100644 --- a/Eigen/src/Core/arch/Default/Settings.h +++ b/Eigen/src/Core/arch/Default/Settings.h @@ -52,7 +52,7 @@ * Typically for a single-threaded application you would set that to 25% of the size of your CPU caches in bytes */ #ifndef EIGEN_TUNE_FOR_CPU_CACHE_SIZE -#define EIGEN_TUNE_FOR_CPU_CACHE_SIZE (sizeof(float)*256*256) +#define EIGEN_TUNE_FOR_CPU_CACHE_SIZE (sizeof(float)*512*512) #endif /** Defines the maximal width of the blocks used in the triangular product and solver diff --git a/Eigen/src/Core/arch/NEON/PacketMath.h b/Eigen/src/Core/arch/NEON/PacketMath.h index 96c75101c..d4dd33322 100644 --- a/Eigen/src/Core/arch/NEON/PacketMath.h +++ b/Eigen/src/Core/arch/NEON/PacketMath.h @@ -32,7 +32,7 @@ #endif #ifndef EIGEN_TUNE_FOR_CPU_CACHE_SIZE -#define EIGEN_TUNE_FOR_CPU_CACHE_SIZE 4*96*96 +#define EIGEN_TUNE_FOR_CPU_CACHE_SIZE 4*192*192 #endif // FIXME NEON has 16 quad registers, but since the current register allocator diff --git a/Eigen/src/Core/products/CoeffBasedProduct.h b/Eigen/src/Core/products/CoeffBasedProduct.h index 170641589..43477282c 100644 --- a/Eigen/src/Core/products/CoeffBasedProduct.h +++ b/Eigen/src/Core/products/CoeffBasedProduct.h @@ -54,6 +54,8 @@ struct ei_traits<CoeffBasedProduct<LhsNested,RhsNested,NestingFlags> > typedef typename ei_scalar_product_traits<typename _LhsNested::Scalar, typename _RhsNested::Scalar>::ReturnType Scalar; typedef typename ei_promote_storage_type<typename ei_traits<_LhsNested>::StorageKind, typename ei_traits<_RhsNested>::StorageKind>::ret StorageKind; + typedef typename ei_promote_index_type<typename ei_traits<_LhsNested>::Index, + typename ei_traits<_RhsNested>::Index>::type Index; enum { LhsCoeffReadCost = _LhsNested::CoeffReadCost, diff --git a/Eigen/src/Core/products/GeneralBlockPanelKernel.h b/Eigen/src/Core/products/GeneralBlockPanelKernel.h index d81715528..be20be833 100644 --- a/Eigen/src/Core/products/GeneralBlockPanelKernel.h +++ b/Eigen/src/Core/products/GeneralBlockPanelKernel.h @@ -25,13 +25,156 @@ #ifndef EIGEN_GENERAL_BLOCK_PANEL_H #define EIGEN_GENERAL_BLOCK_PANEL_H -#ifndef EIGEN_EXTERN_INSTANTIATIONS +/** \internal */ +inline void ei_manage_caching_sizes(Action action, std::ptrdiff_t* a=0, std::ptrdiff_t* b=0, std::ptrdiff_t* c=0, int scalar_size = 0) +{ + const int nbScalarSizes = 12; + static std::ptrdiff_t m_maxK[nbScalarSizes]; + static std::ptrdiff_t m_maxM[nbScalarSizes]; + static std::ptrdiff_t m_maxN[nbScalarSizes]; + static std::ptrdiff_t m_l1CacheSize = 0; + static std::ptrdiff_t m_l2CacheSize = 0; + if(m_l1CacheSize==0) + { + // initialization + m_l1CacheSize = EIGEN_TUNE_FOR_CPU_CACHE_SIZE; + m_l2CacheSize = 32*EIGEN_TUNE_FOR_CPU_CACHE_SIZE; + ei_manage_caching_sizes(SetAction,&m_l1CacheSize, &m_l2CacheSize); + } + + if(action==SetAction && scalar_size==0) + { + // set the cpu cache size and cache all block sizes from a global cache size in byte + ei_internal_assert(a!=0 && b!=0 && c==0); + m_l1CacheSize = *a; + m_l2CacheSize = *b; + int ss = 4; + for(int i=0; i<nbScalarSizes;++i,ss+=4) + { + // Round the block size such that it is a multiple of 64/ss. + // This is to make sure the block size are multiple of the register block sizes. + // And in the worst case we ensure an even number. + std::ptrdiff_t rb = 64/ss; + if(rb==0) rb = 1; + m_maxK[i] = 4 * std::ptrdiff_t(ei_sqrt<float>(m_l1CacheSize/(64*ss))); + m_maxM[i] = 2 * m_maxK[i]; + m_maxN[i] = ((m_l2CacheSize / (2 * m_maxK[i] * ss))/4)*4; + } + } + else if(action==SetAction && scalar_size!=0) + { + // set the block sizes for the given scalar type (represented as its size) + ei_internal_assert(a!=0 && b!=0 && c!=0); + int i = std::max((scalar_size>>2)-1,0); + if(i<nbScalarSizes) + { + m_maxK[i] = *a; + m_maxM[i] = *b; + m_maxN[i] = *c; + } + } + else if(action==GetAction && scalar_size==0) + { + ei_internal_assert(a!=0 && b!=0 && c==0); + *a = m_l1CacheSize; + *b = m_l2CacheSize; + } + else if(action==GetAction && scalar_size!=0) + { + ei_internal_assert(a!=0 && b!=0 && c!=0); + int i = std::min(std::max((scalar_size>>2),1),nbScalarSizes)-1; + *a = m_maxK[i]; + *b = m_maxM[i]; + *c = m_maxN[i]; + } + else + { + ei_internal_assert(false); + } +} + +/** \returns the currently set level 1 cpu cache size (in bytes) used to estimate the ideal blocking size parameters. + * \sa setCpuCacheSize */ +inline std::ptrdiff_t l1CacheSize() +{ + std::ptrdiff_t l1, l2; + ei_manage_caching_sizes(GetAction, &l1, &l2); + return l1; +} + +/** \returns the currently set level 2 cpu cache size (in bytes) used to estimate the ideal blocking size parameters. + * \sa setCpuCacheSize */ +inline std::ptrdiff_t l2CacheSize() +{ + std::ptrdiff_t l1, l2; + ei_manage_caching_sizes(GetAction, &l1, &l2); + return l2; +} + +/** Set the cpu L1 and L2 cache sizes (in bytes). + * These values are use to adjust the size of the blocks + * for the algorithms working per blocks. + * + * This function also automatically set the blocking size parameters + * for each scalar type using the following rules: + * \code + * max_k = 4 * sqrt(l1/(64*sizeof(Scalar))); + * max_m = 2 * k; + * max_n = l2/(2*max_k*sizeof(Scalar)); + * \endcode + * overwriting custom values set using the setBlockingSizes function. + * + * See setBlockingSizes() for an explanation about the meaning of these parameters. + * + * \sa setBlockingSizes */ +inline void setCpuCacheSizes(std::ptrdiff_t l1, std::ptrdiff_t l2) +{ + ei_manage_caching_sizes(SetAction, &l1, &l2); +} + +/** \brief Set the blocking size parameters \a maxK, \a maxM and \a maxN for the scalar type \a Scalar. + * + * \param[in] maxK the size of the L1 and L2 blocks along the k dimension + * \param[in] maxM the size of the L1 blocks along the m dimension + * \param[in] maxN the size of the L2 blocks along the n dimension + * + * This function sets the blocking size parameters for matrix products and related algorithms. + * More precisely, let A * B be a m x k by k x n matrix product. Then Eigen's product like + * algorithms perform L2 blocking on B with horizontal panels of size maxK x maxN, + * and L1 blocking on A with blocks of size maxM x maxK. + * + * Theoretically, for best performances maxM should be closed to maxK and maxM * maxK should + * note exceed half of the L1 cache. Likewise, maxK * maxM should be smaller than the L2 cache. + * + * Note that in practice there is no distinction between scalar types of same size. + * + * \sa setCpuCacheSizes */ +template<typename Scalar> +void setBlockingSizes(std::ptrdiff_t maxK, std::ptrdiff_t maxM, std::ptrdiff_t maxN) +{ + std::ptrdiff_t k, m, n; + typedef ei_product_blocking_traits<Scalar> Traits; + k = ((maxK)/4)*4; + m = ((maxM)/Traits::mr)*Traits::mr; + n = ((maxN)/Traits::nr)*Traits::nr; + ei_manage_caching_sizes(SetAction,&k,&m,&n,sizeof(Scalar)); +} + +/** \returns in \a makK, \a maxM and \a maxN the blocking size parameters for the scalar type \a Scalar. + * + * See setBlockingSizes for an explanation about the meaning of these parameters. + * + * \sa setBlockingSizes */ +template<typename Scalar> +void getBlockingSizes(std::ptrdiff_t& maxK, std::ptrdiff_t& maxM, std::ptrdiff_t& maxN) +{ + ei_manage_caching_sizes(GetAction,&maxK,&maxM,&maxN,sizeof(Scalar)); +} #ifdef EIGEN_HAS_FUSE_CJMADD -#define CJMADD(A,B,C,T) C = cj.pmadd(A,B,C); + #define CJMADD(A,B,C,T) C = cj.pmadd(A,B,C); #else -#define CJMADD(A,B,C,T) T = B; T = cj.pmul(A,T); C = ei_padd(C,T); -// #define CJMADD(A,B,C,T) T = A; T = cj.pmul(T,B); C = ei_padd(C,T); + #define CJMADD(A,B,C,T) T = B; T = cj.pmul(A,T); C = ei_padd(C,T); #endif // optimized GEneral packed Block * packed Panel product kernel @@ -762,6 +905,4 @@ struct ei_gemm_pack_rhs<Scalar, Index, nr, RowMajor, PanelMode> } }; -#endif // EIGEN_EXTERN_INSTANTIATIONS - #endif // EIGEN_GENERAL_BLOCK_PANEL_H diff --git a/Eigen/src/Core/products/GeneralMatrixMatrix.h b/Eigen/src/Core/products/GeneralMatrixMatrix.h index 991977c1f..3513d118e 100644 --- a/Eigen/src/Core/products/GeneralMatrixMatrix.h +++ b/Eigen/src/Core/products/GeneralMatrixMatrix.h @@ -25,8 +25,6 @@ #ifndef EIGEN_GENERAL_MATRIX_MATRIX_H #define EIGEN_GENERAL_MATRIX_MATRIX_H -#ifndef EIGEN_EXTERN_INSTANTIATIONS - /* Specialization for a row-major destination matrix => simple transposition of the product */ template< typename Scalar, typename Index, @@ -77,8 +75,13 @@ static void run(Index rows, Index cols, Index depth, typedef typename ei_packet_traits<Scalar>::type PacketType; typedef ei_product_blocking_traits<Scalar> Blocking; - Index kc = std::min<Index>(Blocking::Max_kc,depth); // cache block size along the K direction - Index mc = std::min<Index>(Blocking::Max_mc,rows); // cache block size along the M direction + Index kc; // cache block size along the K direction + Index mc; // cache block size along the M direction + Index nc; // cache block size along the N direction + getBlockingSizes<Scalar>(kc, mc, nc); + kc = std::min<Index>(kc,depth); + mc = std::min<Index>(mc,rows); + nc = std::min<Index>(nc,cols); ei_gemm_pack_rhs<Scalar, Index, Blocking::nr, RhsStorageOrder> pack_rhs; ei_gemm_pack_lhs<Scalar, Index, Blocking::mr, LhsStorageOrder> pack_lhs; @@ -159,7 +162,8 @@ static void run(Index rows, Index cols, Index depth, else #endif // EIGEN_HAS_OPENMP { - (void)info; // info is not used + EIGEN_UNUSED_VARIABLE(info); + // this is the sequential version! Scalar* blockA = ei_aligned_stack_new(Scalar, kc*mc); std::size_t sizeB = kc*Blocking::PacketSize*Blocking::nr + kc*cols; @@ -203,8 +207,6 @@ static void run(Index rows, Index cols, Index depth, }; -#endif // EIGEN_EXTERN_INSTANTIATIONS - /********************************************************************************* * Specialization of GeneralProduct<> for "large" GEMM, i.e., * implementation of the high level wrapper to ei_general_matrix_matrix_product @@ -239,7 +241,9 @@ struct ei_gemm_functor Index sharedBlockBSize() const { - return std::min<Index>(ei_product_blocking_traits<Scalar>::Max_kc,m_rhs.rows()) * m_rhs.cols(); + Index maxKc, maxMc, maxNc; + getBlockingSizes<Scalar>(maxKc, maxMc, maxNc); + return std::min<Index>(maxKc,m_rhs.rows()) * m_rhs.cols(); } protected: diff --git a/Eigen/src/Core/products/Parallelizer.h b/Eigen/src/Core/products/Parallelizer.h index 5e4eb6f1e..588f78b4c 100644 --- a/Eigen/src/Core/products/Parallelizer.h +++ b/Eigen/src/Core/products/Parallelizer.h @@ -25,6 +25,50 @@ #ifndef EIGEN_PARALLELIZER_H #define EIGEN_PARALLELIZER_H +/** \internal */ +inline void ei_manage_multi_threading(Action action, int* v) +{ + static int m_maxThreads = -1; + + if(action==SetAction) + { + ei_internal_assert(v!=0); + m_maxThreads = *v; + } + else if(action==GetAction) + { + ei_internal_assert(v!=0); + #ifdef EIGEN_HAS_OPENMP + if(m_maxThreads>0) + *v = m_maxThreads; + else + *v = omp_get_max_threads(); + #else + *v = 1; + #endif + } + else + { + ei_internal_assert(false); + } +} + +/** \returns the max number of threads reserved for Eigen + * \sa setNbThreads */ +inline int nbThreads() +{ + int ret; + ei_manage_multi_threading(GetAction, &ret); + return ret; +} + +/** Sets the max number of threads reserved for Eigen + * \sa nbThreads */ +inline void setNbThreads(int v) +{ + ei_manage_multi_threading(SetAction, &v); +} + template<typename BlockBScalar, typename Index> struct GemmParallelInfo { GemmParallelInfo() : sync(-1), users(0), rhs_start(0), rhs_length(0), blockB(0) {} @@ -57,10 +101,10 @@ void ei_parallelize_gemm(const Functor& func, Index rows, Index cols) // 2- compute the maximal number of threads from the size of the product: // FIXME this has to be fine tuned - Index max_threads = std::max(1,rows / 32); + Index max_threads = std::max<Index>(1,rows / 32); // 3 - compute the number of threads we are going to use - Index threads = std::min<Index>(omp_get_max_threads(), max_threads); + Index threads = std::min<Index>(nbThreads(), max_threads); if(threads==1) return func(0,rows, 0,cols); @@ -71,7 +115,8 @@ void ei_parallelize_gemm(const Functor& func, Index rows, Index cols) typedef typename Functor::BlockBScalar BlockBScalar; BlockBScalar* sharedBlockB = new BlockBScalar[func.sharedBlockBSize()]; - GemmParallelInfo<BlockBScalar>* info = new GemmParallelInfo<BlockBScalar>[threads]; + GemmParallelInfo<BlockBScalar,Index>* info = new + GemmParallelInfo<BlockBScalar,Index>[threads]; #pragma omp parallel for schedule(static,1) num_threads(threads) for(Index i=0; i<threads; ++i) diff --git a/Eigen/src/Core/util/BlasUtil.h b/Eigen/src/Core/util/BlasUtil.h index 6cbd26689..24d27bce2 100644 --- a/Eigen/src/Core/util/BlasUtil.h +++ b/Eigen/src/Core/util/BlasUtil.h @@ -139,7 +139,7 @@ struct ei_product_blocking_traits mr = 2 * PacketSize, // max cache block size along the K direction - Max_kc = 8 * ei_meta_sqrt<EIGEN_TUNE_FOR_CPU_CACHE_SIZE/(64*sizeof(Scalar))>::ret, + Max_kc = 4 * ei_meta_sqrt<EIGEN_TUNE_FOR_CPU_CACHE_SIZE/(64*sizeof(Scalar))>::ret, // max cache block size along the M direction Max_mc = 2*Max_kc @@ -162,7 +162,7 @@ template<typename XprType> struct ei_blas_traits && ( /* Uncomment this when the low-level matrix-vector product functions support strided vectors bool(XprType::IsVectorAtCompileTime) || */ - int(ei_inner_stride_at_compile_time<XprType>::ret) == 1) + int(ei_inner_stride_at_compile_time<XprType>::ret) <= 1) ) ? 1 : 0 }; typedef typename ei_meta_if<bool(HasUsableDirectAccess), diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index e4dbc4aef..2335a3f08 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h @@ -259,6 +259,8 @@ namespace Architecture enum { CoeffBasedProductMode, LazyCoeffBasedProductMode, OuterProduct, InnerProduct, GemvProduct, GemmProduct }; +enum Action {GetAction, SetAction}; + /** The type used to identify a dense storage. */ struct Dense {}; diff --git a/Eigen/src/Core/util/DisableMSVCWarnings.h b/Eigen/src/Core/util/DisableMSVCWarnings.h index dcc71143d..7bab741ff 100644 --- a/Eigen/src/Core/util/DisableMSVCWarnings.h +++ b/Eigen/src/Core/util/DisableMSVCWarnings.h @@ -3,7 +3,8 @@ // 4273 - QtAlignedMalloc, inconsistent DLL linkage // 4100 - unreferenced formal parameter (occurred e.g. in aligned_allocator::destroy(pointer p)) // 4101 - unreferenced local variable + // 4324 - structure was padded due to declspec(align()) // 4512 - assignment operator could not be generated #pragma warning( push ) - #pragma warning( disable : 4100 4101 4181 4244 4127 4211 4273 4512 4522 4717 ) + #pragma warning( disable : 4100 4101 4181 4244 4127 4211 4273 4324 4512 4522 4717 ) #endif diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index b3bc9c161..6a9a7941c 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -77,6 +77,8 @@ template<typename _DiagonalVectorType> class DiagonalWrapper; template<typename _Scalar, int SizeAtCompileTime, int MaxSizeAtCompileTime=SizeAtCompileTime> class DiagonalMatrix; template<typename MatrixType, typename DiagonalType, int ProductOrder> class DiagonalProduct; template<typename MatrixType, int Index> class Diagonal; +template<int SizeAtCompileTime, int MaxSizeAtCompileTime = SizeAtCompileTime> class PermutationMatrix; +template<int SizeAtCompileTime, int MaxSizeAtCompileTime = SizeAtCompileTime> class Transpositions; template<int InnerStrideAtCompileTime, int OuterStrideAtCompileTime> class Stride; template<typename MatrixType, int MapOptions=Unaligned, typename StrideType = Stride<0,0> > class Map; @@ -158,7 +160,7 @@ template<typename MatrixType> class FullPivHouseholderQR; template<typename MatrixType> class SVD; template<typename MatrixType, unsigned int Options = 0> class JacobiSVD; template<typename MatrixType, int UpLo = Lower> class LLT; -template<typename MatrixType> class LDLT; +template<typename MatrixType, int UpLo = Lower> class LDLT; template<typename VectorsType, typename CoeffsType, int Side=OnTheLeft> class HouseholderSequence; template<typename Scalar> class PlanarRotation; diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 3a65fb807..6a05ee87a 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -98,10 +98,6 @@ #define EIGEN_DEFAULT_DENSE_INDEX_TYPE std::ptrdiff_t #endif -#ifndef EIGEN_DEFAULT_SPARSE_INDEX_TYPE -#define EIGEN_DEFAULT_SPARSE_INDEX_TYPE int -#endif - /** Allows to disable some optimizations which might affect the accuracy of the result. * Such optimization are enabled by default, and set EIGEN_FAST_MATH to 0 to disable them. * They currently include: @@ -180,6 +176,9 @@ #define EIGEN_UNUSED #endif +// Suppresses 'unused variable' warnings. +#define EIGEN_UNUSED_VARIABLE(var) (void)var; + #if (defined __GNUC__) #define EIGEN_ASM_COMMENT(X) asm("#"X) #else @@ -269,13 +268,13 @@ * documentation in a single line. **/ -#define EIGEN_GENERIC_PUBLIC_INTERFACE_NEW(Derived) \ +#define EIGEN_GENERIC_PUBLIC_INTERFACE(Derived) \ typedef typename Eigen::ei_traits<Derived>::Scalar Scalar; /*!< \brief Numeric type, e.g. float, double, int or std::complex<float>. */ \ typedef typename Eigen::NumTraits<Scalar>::Real RealScalar; /*!< \brief The underlying numeric type for composed scalar types. \details In cases where Scalar is e.g. std::complex<T>, T were corresponding to RealScalar. */ \ typedef typename Base::CoeffReturnType CoeffReturnType; /*!< \brief The return type for coefficient access. \details Depending on whether the object allows direct coefficient access (e.g. for a MatrixXd), this type is either 'const Scalar&' or simply 'Scalar' for objects that do not allow direct coefficient access. */ \ typedef typename Eigen::ei_nested<Derived>::type Nested; \ typedef typename Eigen::ei_traits<Derived>::StorageKind StorageKind; \ - typedef typename Eigen::ei_index<StorageKind>::type Index; \ + typedef typename Eigen::ei_traits<Derived>::Index Index; \ enum { RowsAtCompileTime = Eigen::ei_traits<Derived>::RowsAtCompileTime, \ ColsAtCompileTime = Eigen::ei_traits<Derived>::ColsAtCompileTime, \ Flags = Eigen::ei_traits<Derived>::Flags, \ @@ -292,7 +291,7 @@ typedef typename Base::CoeffReturnType CoeffReturnType; /*!< \brief The return type for coefficient access. \details Depending on whether the object allows direct coefficient access (e.g. for a MatrixXd), this type is either 'const Scalar&' or simply 'Scalar' for objects that do not allow direct coefficient access. */ \ typedef typename Eigen::ei_nested<Derived>::type Nested; \ typedef typename Eigen::ei_traits<Derived>::StorageKind StorageKind; \ - typedef typename Eigen::ei_index<StorageKind>::type Index; \ + typedef typename Eigen::ei_traits<Derived>::Index Index; \ enum { RowsAtCompileTime = Eigen::ei_traits<Derived>::RowsAtCompileTime, \ ColsAtCompileTime = Eigen::ei_traits<Derived>::ColsAtCompileTime, \ MaxRowsAtCompileTime = Eigen::ei_traits<Derived>::MaxRowsAtCompileTime, \ diff --git a/Eigen/src/Core/util/Memory.h b/Eigen/src/Core/util/Memory.h index 6b202dbc8..c67b9774f 100644 --- a/Eigen/src/Core/util/Memory.h +++ b/Eigen/src/Core/util/Memory.h @@ -218,7 +218,7 @@ inline void ei_aligned_free(void *ptr) **/ inline void* ei_aligned_realloc(void *ptr, size_t new_size, size_t old_size) { - (void)old_size; // Suppress 'unused variable' warning. Seen in boost tee. + EIGEN_UNUSED_VARIABLE(old_size); void *result; #if !EIGEN_ALIGN diff --git a/Eigen/src/Core/util/XprHelper.h b/Eigen/src/Core/util/XprHelper.h index cef7874a9..adb878665 100644 --- a/Eigen/src/Core/util/XprHelper.h +++ b/Eigen/src/Core/util/XprHelper.h @@ -42,13 +42,14 @@ class ei_no_assignment_operator ei_no_assignment_operator& operator=(const ei_no_assignment_operator&); }; -template<typename StorageKind> struct ei_index {}; +typedef EIGEN_DEFAULT_DENSE_INDEX_TYPE DenseIndex; -template<> -struct ei_index<Dense> -{ typedef EIGEN_DEFAULT_DENSE_INDEX_TYPE type; }; - -typedef ei_index<Dense>::type DenseIndex; +/** \internal return the index type with the largest number of bits */ +template<typename I1, typename I2> +struct ei_promote_index_type +{ + typedef typename ei_meta_if<(sizeof(I1)<sizeof(I2)), I2, I1>::ret type; +}; /** \internal If the template parameter Value is Dynamic, this class is just a wrapper around a T variable that * can be accessed using value() and setValue(). diff --git a/Eigen/src/Eigenvalues/ComplexEigenSolver.h b/Eigen/src/Eigenvalues/ComplexEigenSolver.h index f56815c15..a164aaae6 100644 --- a/Eigen/src/Eigenvalues/ComplexEigenSolver.h +++ b/Eigen/src/Eigenvalues/ComplexEigenSolver.h @@ -27,6 +27,9 @@ #ifndef EIGEN_COMPLEX_EIGEN_SOLVER_H #define EIGEN_COMPLEX_EIGEN_SOLVER_H +#include "./EigenvaluesCommon.h" +#include "./ComplexSchur.h" + /** \eigenvalues_module \ingroup Eigenvalues_Module * \nonstableyet * @@ -56,7 +59,10 @@ template<typename _MatrixType> class ComplexEigenSolver { public: + + /** \brief Synonym for the template parameter \p _MatrixType. */ typedef _MatrixType MatrixType; + enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, @@ -65,12 +71,12 @@ template<typename _MatrixType> class ComplexEigenSolver MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime }; - /** \brief Scalar type for matrices of type \p _MatrixType. */ + /** \brief Scalar type for matrices of type #MatrixType. */ typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits<Scalar>::Real RealScalar; typedef typename MatrixType::Index Index; - /** \brief Complex scalar type for \p _MatrixType. + /** \brief Complex scalar type for #MatrixType. * * This is \c std::complex<Scalar> if #Scalar is real (e.g., * \c float or \c double) and just \c Scalar if #Scalar is @@ -81,14 +87,14 @@ template<typename _MatrixType> class ComplexEigenSolver /** \brief Type for vector of eigenvalues as returned by eigenvalues(). * * This is a column vector with entries of type #ComplexScalar. - * The length of the vector is the size of \p _MatrixType. + * The length of the vector is the size of #MatrixType. */ typedef Matrix<ComplexScalar, ColsAtCompileTime, 1, Options, MaxColsAtCompileTime, 1> EigenvalueType; /** \brief Type for matrix of eigenvectors as returned by eigenvectors(). * * This is a square matrix with entries of type #ComplexScalar. - * The size is the same as the size of \p _MatrixType. + * The size is the same as the size of #MatrixType. */ typedef Matrix<ComplexScalar, RowsAtCompileTime, ColsAtCompileTime, Options, MaxRowsAtCompileTime, ColsAtCompileTime> EigenvectorType; @@ -102,6 +108,7 @@ template<typename _MatrixType> class ComplexEigenSolver m_eivalues(), m_schur(), m_isInitialized(false), + m_eigenvectorsOk(false), m_matX() {} @@ -116,40 +123,46 @@ template<typename _MatrixType> class ComplexEigenSolver m_eivalues(size), m_schur(size), m_isInitialized(false), + m_eigenvectorsOk(false), m_matX(size, size) {} /** \brief Constructor; computes eigendecomposition of given matrix. * * \param[in] matrix Square matrix whose eigendecomposition is to be computed. + * \param[in] computeEigenvectors If true, both the eigenvectors and the + * eigenvalues are computed; if false, only the eigenvalues are + * computed. * * This constructor calls compute() to compute the eigendecomposition. */ - ComplexEigenSolver(const MatrixType& matrix) + ComplexEigenSolver(const MatrixType& matrix, bool computeEigenvectors = true) : m_eivec(matrix.rows(),matrix.cols()), m_eivalues(matrix.cols()), m_schur(matrix.rows()), m_isInitialized(false), + m_eigenvectorsOk(false), m_matX(matrix.rows(),matrix.cols()) { - compute(matrix); + compute(matrix, computeEigenvectors); } /** \brief Returns the eigenvectors of given matrix. * * \returns A const reference to the matrix whose columns are the eigenvectors. * - * It is assumed that either the constructor - * ComplexEigenSolver(const MatrixType& matrix) or the member - * function compute(const MatrixType& matrix) has been called - * before to compute the eigendecomposition of a matrix. This - * function returns a matrix whose columns are the - * eigenvectors. Column \f$ k \f$ is an eigenvector - * corresponding to eigenvalue number \f$ k \f$ as returned by - * eigenvalues(). The eigenvectors are normalized to have - * (Euclidean) norm equal to one. The matrix returned by this - * function is the matrix \f$ V \f$ in the eigendecomposition \f$ - * A = V D V^{-1} \f$, if it exists. + * \pre Either the constructor + * ComplexEigenSolver(const MatrixType& matrix, bool) or the member + * function compute(const MatrixType& matrix, bool) has been called before + * to compute the eigendecomposition of a matrix, and + * \p computeEigenvectors was set to true (the default). + * + * This function returns a matrix whose columns are the eigenvectors. Column + * \f$ k \f$ is an eigenvector corresponding to eigenvalue number \f$ k + * \f$ as returned by eigenvalues(). The eigenvectors are normalized to + * have (Euclidean) norm equal to one. The matrix returned by this + * function is the matrix \f$ V \f$ in the eigendecomposition \f$ A = V D + * V^{-1} \f$, if it exists. * * Example: \include ComplexEigenSolver_eigenvectors.cpp * Output: \verbinclude ComplexEigenSolver_eigenvectors.out @@ -157,6 +170,7 @@ template<typename _MatrixType> class ComplexEigenSolver const EigenvectorType& eigenvectors() const { ei_assert(m_isInitialized && "ComplexEigenSolver is not initialized."); + ei_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues."); return m_eivec; } @@ -164,11 +178,12 @@ template<typename _MatrixType> class ComplexEigenSolver * * \returns A const reference to the column vector containing the eigenvalues. * - * It is assumed that either the constructor - * ComplexEigenSolver(const MatrixType& matrix) or the member - * function compute(const MatrixType& matrix) has been called - * before to compute the eigendecomposition of a matrix. This - * function returns a column vector containing the + * \pre Either the constructor + * ComplexEigenSolver(const MatrixType& matrix, bool) or the member + * function compute(const MatrixType& matrix, bool) has been called before + * to compute the eigendecomposition of a matrix. + * + * This function returns a column vector containing the * eigenvalues. Eigenvalues are repeated according to their * algebraic multiplicity, so there are as many eigenvalues as * rows in the matrix. @@ -185,10 +200,15 @@ template<typename _MatrixType> class ComplexEigenSolver /** \brief Computes eigendecomposition of given matrix. * * \param[in] matrix Square matrix whose eigendecomposition is to be computed. + * \param[in] computeEigenvectors If true, both the eigenvectors and the + * eigenvalues are computed; if false, only the eigenvalues are + * computed. + * \returns Reference to \c *this * - * This function computes the eigenvalues and eigenvectors of \p - * matrix. The eigenvalues() and eigenvectors() functions can be - * used to retrieve the computed eigendecomposition. + * This function computes the eigenvalues of the complex matrix \p matrix. + * The eigenvalues() function can be used to retrieve them. If + * \p computeEigenvectors is true, then the eigenvectors are also computed + * and can be retrieved by calling eigenvectors(). * * The matrix is first reduced to Schur form using the * ComplexSchur class. The Schur decomposition is then used to @@ -201,31 +221,62 @@ template<typename _MatrixType> class ComplexEigenSolver * Example: \include ComplexEigenSolver_compute.cpp * Output: \verbinclude ComplexEigenSolver_compute.out */ - void compute(const MatrixType& matrix); + ComplexEigenSolver& compute(const MatrixType& matrix, bool computeEigenvectors = true); + + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was succesful, \c NoConvergence otherwise. + */ + ComputationInfo info() const + { + ei_assert(m_isInitialized && "ComplexEigenSolver is not initialized."); + return m_schur.info(); + } protected: EigenvectorType m_eivec; EigenvalueType m_eivalues; ComplexSchur<MatrixType> m_schur; bool m_isInitialized; + bool m_eigenvectorsOk; EigenvectorType m_matX; + + private: + void doComputeEigenvectors(RealScalar matrixnorm); + void sortEigenvalues(bool computeEigenvectors); }; template<typename MatrixType> -void ComplexEigenSolver<MatrixType>::compute(const MatrixType& matrix) +ComplexEigenSolver<MatrixType>& ComplexEigenSolver<MatrixType>::compute(const MatrixType& matrix, bool computeEigenvectors) { // this code is inspired from Jampack assert(matrix.cols() == matrix.rows()); - const Index n = matrix.cols(); - const RealScalar matrixnorm = matrix.norm(); - // Step 1: Do a complex Schur decomposition, A = U T U^* + // Do a complex Schur decomposition, A = U T U^* // The eigenvalues are on the diagonal of T. - m_schur.compute(matrix); - m_eivalues = m_schur.matrixT().diagonal(); + m_schur.compute(matrix, computeEigenvectors); + + if(m_schur.info() == Success) + { + m_eivalues = m_schur.matrixT().diagonal(); + if(computeEigenvectors) + doComputeEigenvectors(matrix.norm()); + sortEigenvalues(computeEigenvectors); + } + + m_isInitialized = true; + m_eigenvectorsOk = computeEigenvectors; + return *this; +} + + +template<typename MatrixType> +void ComplexEigenSolver<MatrixType>::doComputeEigenvectors(RealScalar matrixnorm) +{ + const Index n = m_eivalues.size(); - // Step 2: Compute X such that T = X D X^(-1), where D is the diagonal of T. + // Compute X such that T = X D X^(-1), where D is the diagonal of T. // The matrix X is unit triangular. m_matX = EigenvectorType::Zero(n, n); for(Index k=n-1 ; k>=0 ; k--) @@ -248,16 +299,20 @@ void ComplexEigenSolver<MatrixType>::compute(const MatrixType& matrix) } } - // Step 3: Compute V as V = U X; now A = U T U^* = U X D X^(-1) U^* = V D V^(-1) + // Compute V as V = U X; now A = U T U^* = U X D X^(-1) U^* = V D V^(-1) m_eivec.noalias() = m_schur.matrixU() * m_matX; // .. and normalize the eigenvectors for(Index k=0 ; k<n ; k++) { m_eivec.col(k).normalize(); } - m_isInitialized = true; +} + - // Step 4: Sort the eigenvalues +template<typename MatrixType> +void ComplexEigenSolver<MatrixType>::sortEigenvalues(bool computeEigenvectors) +{ + const Index n = m_eivalues.size(); for (Index i=0; i<n; i++) { Index k; @@ -266,11 +321,11 @@ void ComplexEigenSolver<MatrixType>::compute(const MatrixType& matrix) { k += i; std::swap(m_eivalues[k],m_eivalues[i]); - m_eivec.col(i).swap(m_eivec.col(k)); + if(computeEigenvectors) + m_eivec.col(i).swap(m_eivec.col(k)); } } } - #endif // EIGEN_COMPLEX_EIGEN_SOLVER_H diff --git a/Eigen/src/Eigenvalues/ComplexSchur.h b/Eigen/src/Eigenvalues/ComplexSchur.h index 673cb46f9..6a8daebb8 100644 --- a/Eigen/src/Eigenvalues/ComplexSchur.h +++ b/Eigen/src/Eigenvalues/ComplexSchur.h @@ -27,6 +27,9 @@ #ifndef EIGEN_COMPLEX_SCHUR_H #define EIGEN_COMPLEX_SCHUR_H +#include "./EigenvaluesCommon.h" +#include "./HessenbergDecomposition.h" + template<typename MatrixType, bool IsComplex> struct ei_complex_schur_reduce_to_hessenberg; /** \eigenvalues_module \ingroup Eigenvalues_Module @@ -110,21 +113,21 @@ template<typename _MatrixType> class ComplexSchur /** \brief Constructor; computes Schur decomposition of given matrix. * - * \param[in] matrix Square matrix whose Schur decomposition is to be computed. - * \param[in] skipU If true, then the unitary matrix U in the decomposition is not computed. + * \param[in] matrix Square matrix whose Schur decomposition is to be computed. + * \param[in] computeU If true, both T and U are computed; if false, only T is computed. * * This constructor calls compute() to compute the Schur decomposition. * * \sa matrixT() and matrixU() for examples. */ - ComplexSchur(const MatrixType& matrix, bool skipU = false) + ComplexSchur(const MatrixType& matrix, bool computeU = true) : m_matT(matrix.rows(),matrix.cols()), m_matU(matrix.rows(),matrix.cols()), m_hess(matrix.rows()), m_isInitialized(false), m_matUisUptodate(false) { - compute(matrix, skipU); + compute(matrix, computeU); } /** \brief Returns the unitary matrix in the Schur decomposition. @@ -132,10 +135,10 @@ template<typename _MatrixType> class ComplexSchur * \returns A const reference to the matrix U. * * It is assumed that either the constructor - * ComplexSchur(const MatrixType& matrix, bool skipU) or the - * member function compute(const MatrixType& matrix, bool skipU) + * ComplexSchur(const MatrixType& matrix, bool computeU) or the + * member function compute(const MatrixType& matrix, bool computeU) * has been called before to compute the Schur decomposition of a - * matrix, and that \p skipU was set to false (the default + * matrix, and that \p computeU was set to true (the default * value). * * Example: \include ComplexSchur_matrixU.cpp @@ -153,8 +156,8 @@ template<typename _MatrixType> class ComplexSchur * \returns A const reference to the matrix T. * * It is assumed that either the constructor - * ComplexSchur(const MatrixType& matrix, bool skipU) or the - * member function compute(const MatrixType& matrix, bool skipU) + * ComplexSchur(const MatrixType& matrix, bool computeU) or the + * member function compute(const MatrixType& matrix, bool computeU) * has been called before to compute the Schur decomposition of a * matrix. * @@ -174,7 +177,8 @@ template<typename _MatrixType> class ComplexSchur /** \brief Computes Schur decomposition of given matrix. * * \param[in] matrix Square matrix whose Schur decomposition is to be computed. - * \param[in] skipU If true, then the unitary matrix U in the decomposition is not computed. + * \param[in] computeU If true, both T and U are computed; if false, only T is computed. + * \returns Reference to \c *this * * The Schur decomposition is computed by first reducing the * matrix to Hessenberg form using the class @@ -182,24 +186,42 @@ template<typename _MatrixType> class ComplexSchur * to triangular form by performing QR iterations with a single * shift. The cost of computing the Schur decomposition depends * on the number of iterations; as a rough guide, it may be taken + * on the number of iterations; as a rough guide, it may be taken * to be \f$25n^3\f$ complex flops, or \f$10n^3\f$ complex flops - * if \a skipU is true. + * if \a computeU is false. * * Example: \include ComplexSchur_compute.cpp * Output: \verbinclude ComplexSchur_compute.out */ - void compute(const MatrixType& matrix, bool skipU = false); + ComplexSchur& compute(const MatrixType& matrix, bool computeU = true); + + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was succesful, \c NoConvergence otherwise. + */ + ComputationInfo info() const + { + ei_assert(m_isInitialized && "RealSchur is not initialized."); + return m_info; + } + + /** \brief Maximum number of iterations. + * + * Maximum number of iterations allowed for an eigenvalue to converge. + */ + static const int m_maxIterations = 30; protected: ComplexMatrixType m_matT, m_matU; HessenbergDecomposition<MatrixType> m_hess; + ComputationInfo m_info; bool m_isInitialized; bool m_matUisUptodate; private: bool subdiagonalEntryIsNeglegible(Index i); ComplexScalar computeShift(Index iu, Index iter); - void reduceToTriangularForm(bool skipU); + void reduceToTriangularForm(bool computeU); friend struct ei_complex_schur_reduce_to_hessenberg<MatrixType, NumTraits<Scalar>::IsComplex>; }; @@ -295,22 +317,24 @@ typename ComplexSchur<MatrixType>::ComplexScalar ComplexSchur<MatrixType>::compu template<typename MatrixType> -void ComplexSchur<MatrixType>::compute(const MatrixType& matrix, bool skipU) +ComplexSchur<MatrixType>& ComplexSchur<MatrixType>::compute(const MatrixType& matrix, bool computeU) { m_matUisUptodate = false; ei_assert(matrix.cols() == matrix.rows()); if(matrix.cols() == 1) { - m_matU = ComplexMatrixType::Identity(1,1); - if(!skipU) m_matT = matrix.template cast<ComplexScalar>(); + m_matT = matrix.template cast<ComplexScalar>(); + if(computeU) m_matU = ComplexMatrixType::Identity(1,1); + m_info = Success; m_isInitialized = true; - m_matUisUptodate = !skipU; - return; + m_matUisUptodate = computeU; + return *this; } - ei_complex_schur_reduce_to_hessenberg<MatrixType, NumTraits<Scalar>::IsComplex>::run(*this, matrix, skipU); - reduceToTriangularForm(skipU); + ei_complex_schur_reduce_to_hessenberg<MatrixType, NumTraits<Scalar>::IsComplex>::run(*this, matrix, computeU); + reduceToTriangularForm(computeU); + return *this; } /* Reduce given matrix to Hessenberg form */ @@ -318,28 +342,26 @@ template<typename MatrixType, bool IsComplex> struct ei_complex_schur_reduce_to_hessenberg { // this is the implementation for the case IsComplex = true - static void run(ComplexSchur<MatrixType>& _this, const MatrixType& matrix, bool skipU) + static void run(ComplexSchur<MatrixType>& _this, const MatrixType& matrix, bool computeU) { - // TODO skip Q if skipU = true _this.m_hess.compute(matrix); _this.m_matT = _this.m_hess.matrixH(); - if(!skipU) _this.m_matU = _this.m_hess.matrixQ(); + if(computeU) _this.m_matU = _this.m_hess.matrixQ(); } }; template<typename MatrixType> struct ei_complex_schur_reduce_to_hessenberg<MatrixType, false> { - static void run(ComplexSchur<MatrixType>& _this, const MatrixType& matrix, bool skipU) + static void run(ComplexSchur<MatrixType>& _this, const MatrixType& matrix, bool computeU) { typedef typename ComplexSchur<MatrixType>::ComplexScalar ComplexScalar; typedef typename ComplexSchur<MatrixType>::ComplexMatrixType ComplexMatrixType; // Note: m_hess is over RealScalar; m_matT and m_matU is over ComplexScalar - // TODO skip Q if skipU = true _this.m_hess.compute(matrix); _this.m_matT = _this.m_hess.matrixH().template cast<ComplexScalar>(); - if(!skipU) + if(computeU) { // This may cause an allocation which seems to be avoidable MatrixType Q = _this.m_hess.matrixQ(); @@ -350,7 +372,7 @@ struct ei_complex_schur_reduce_to_hessenberg<MatrixType, false> // Reduce the Hessenberg matrix m_matT to triangular form by QR iteration. template<typename MatrixType> -void ComplexSchur<MatrixType>::reduceToTriangularForm(bool skipU) +void ComplexSchur<MatrixType>::reduceToTriangularForm(bool computeU) { // The matrix m_matT is divided in three parts. // Rows 0,...,il-1 are decoupled from the rest because m_matT(il,il-1) is zero. @@ -373,9 +395,9 @@ void ComplexSchur<MatrixType>::reduceToTriangularForm(bool skipU) // if iu is zero then we are done; the whole matrix is triangularized if(iu==0) break; - // if we spent 30 iterations on the current element, we give up + // if we spent too many iterations on the current element, we give up iter++; - if(iter >= 30) break; + if(iter > m_maxIterations) break; // find il, the top row of the active submatrix il = iu-1; @@ -393,7 +415,7 @@ void ComplexSchur<MatrixType>::reduceToTriangularForm(bool skipU) rot.makeGivens(m_matT.coeff(il,il) - shift, m_matT.coeff(il+1,il)); m_matT.rightCols(m_matT.cols()-il).applyOnTheLeft(il, il+1, rot.adjoint()); m_matT.topRows(std::min(il+2,iu)+1).applyOnTheRight(il, il+1, rot); - if(!skipU) m_matU.applyOnTheRight(il, il+1, rot); + if(computeU) m_matU.applyOnTheRight(il, il+1, rot); for(Index i=il+1 ; i<iu ; i++) { @@ -401,19 +423,17 @@ void ComplexSchur<MatrixType>::reduceToTriangularForm(bool skipU) m_matT.coeffRef(i+1,i-1) = ComplexScalar(0); m_matT.rightCols(m_matT.cols()-i).applyOnTheLeft(i, i+1, rot.adjoint()); m_matT.topRows(std::min(i+2,iu)+1).applyOnTheRight(i, i+1, rot); - if(!skipU) m_matU.applyOnTheRight(i, i+1, rot); + if(computeU) m_matU.applyOnTheRight(i, i+1, rot); } } - if(iter >= 30) - { - // FIXME : what to do when iter==MAXITER ?? - // std::cerr << "MAXITER" << std::endl; - return; - } + if(iter <= m_maxIterations) + m_info = Success; + else + m_info = NoConvergence; m_isInitialized = true; - m_matUisUptodate = !skipU; + m_matUisUptodate = computeU; } #endif // EIGEN_COMPLEX_SCHUR_H diff --git a/Eigen/src/Eigenvalues/EigenSolver.h b/Eigen/src/Eigenvalues/EigenSolver.h index 5400fdaf2..04caee658 100644 --- a/Eigen/src/Eigenvalues/EigenSolver.h +++ b/Eigen/src/Eigenvalues/EigenSolver.h @@ -26,6 +26,7 @@ #ifndef EIGEN_EIGENSOLVER_H #define EIGEN_EIGENSOLVER_H +#include "./EigenvaluesCommon.h" #include "./RealSchur.h" /** \eigenvalues_module \ingroup Eigenvalues_Module @@ -57,16 +58,16 @@ * this variant of the eigendecomposition the pseudo-eigendecomposition. * * Call the function compute() to compute the eigenvalues and eigenvectors of - * a given matrix. Alternatively, you can use the - * EigenSolver(const MatrixType&) constructor which computes the eigenvalues - * and eigenvectors at construction time. Once the eigenvalue and eigenvectors - * are computed, they can be retrieved with the eigenvalues() and + * a given matrix. Alternatively, you can use the + * EigenSolver(const MatrixType&, bool) constructor which computes the + * eigenvalues and eigenvectors at construction time. Once the eigenvalue and + * eigenvectors are computed, they can be retrieved with the eigenvalues() and * eigenvectors() functions. The pseudoEigenvalueMatrix() and * pseudoEigenvectors() methods allow the construction of the * pseudo-eigendecomposition. * - * The documentation for EigenSolver(const MatrixType&) contains an example of - * the typical use of this class. + * The documentation for EigenSolver(const MatrixType&, bool) contains an + * example of the typical use of this class. * * \note The implementation is adapted from * <a href="http://math.nist.gov/javanumerics/jama/">JAMA</a> (public domain). @@ -78,7 +79,9 @@ template<typename _MatrixType> class EigenSolver { public: + /** \brief Synonym for the template parameter \p _MatrixType. */ typedef _MatrixType MatrixType; + enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, @@ -87,12 +90,12 @@ template<typename _MatrixType> class EigenSolver MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime }; - /** \brief Scalar type for matrices of type \p _MatrixType. */ + /** \brief Scalar type for matrices of type #MatrixType. */ typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits<Scalar>::Real RealScalar; typedef typename MatrixType::Index Index; - /** \brief Complex scalar type for \p _MatrixType. + /** \brief Complex scalar type for #MatrixType. * * This is \c std::complex<Scalar> if #Scalar is real (e.g., * \c float or \c double) and just \c Scalar if #Scalar is @@ -103,27 +106,27 @@ template<typename _MatrixType> class EigenSolver /** \brief Type for vector of eigenvalues as returned by eigenvalues(). * * This is a column vector with entries of type #ComplexScalar. - * The length of the vector is the size of \p _MatrixType. + * The length of the vector is the size of #MatrixType. */ typedef Matrix<ComplexScalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> EigenvalueType; /** \brief Type for matrix of eigenvectors as returned by eigenvectors(). * * This is a square matrix with entries of type #ComplexScalar. - * The size is the same as the size of \p _MatrixType. + * The size is the same as the size of #MatrixType. */ typedef Matrix<ComplexScalar, RowsAtCompileTime, ColsAtCompileTime, Options, MaxRowsAtCompileTime, MaxColsAtCompileTime> EigenvectorsType; /** \brief Default constructor. * * The default constructor is useful in cases in which the user intends to - * perform decompositions via EigenSolver::compute(const MatrixType&). + * perform decompositions via EigenSolver::compute(const MatrixType&, bool). * * \sa compute() for an example. */ EigenSolver() : m_eivec(), m_eivalues(), m_isInitialized(false), m_realSchur(), m_matT(), m_tmp() {} - /** \brief Default Constructor with memory preallocation + /** \brief Default constructor with memory preallocation * * Like the default constructor but with preallocation of the internal data * according to the specified problem \a size. @@ -133,6 +136,7 @@ template<typename _MatrixType> class EigenSolver : m_eivec(size, size), m_eivalues(size), m_isInitialized(false), + m_eigenvectorsOk(false), m_realSchur(size), m_matT(size, size), m_tmp(size) @@ -141,6 +145,9 @@ template<typename _MatrixType> class EigenSolver /** \brief Constructor; computes eigendecomposition of given matrix. * * \param[in] matrix Square matrix whose eigendecomposition is to be computed. + * \param[in] computeEigenvectors If true, both the eigenvectors and the + * eigenvalues are computed; if false, only the eigenvalues are + * computed. * * This constructor calls compute() to compute the eigenvalues * and eigenvectors. @@ -150,23 +157,26 @@ template<typename _MatrixType> class EigenSolver * * \sa compute() */ - EigenSolver(const MatrixType& matrix) + EigenSolver(const MatrixType& matrix, bool computeEigenvectors = true) : m_eivec(matrix.rows(), matrix.cols()), m_eivalues(matrix.cols()), m_isInitialized(false), + m_eigenvectorsOk(false), m_realSchur(matrix.cols()), m_matT(matrix.rows(), matrix.cols()), m_tmp(matrix.cols()) { - compute(matrix); + compute(matrix, computeEigenvectors); } /** \brief Returns the eigenvectors of given matrix. * * \returns %Matrix whose columns are the (possibly complex) eigenvectors. * - * \pre Either the constructor EigenSolver(const MatrixType&) or the - * member function compute(const MatrixType&) has been called before. + * \pre Either the constructor + * EigenSolver(const MatrixType&,bool) or the member function + * compute(const MatrixType&, bool) has been called before, and + * \p computeEigenvectors was set to true (the default). * * Column \f$ k \f$ of the returned matrix is an eigenvector corresponding * to eigenvalue number \f$ k \f$ as returned by eigenvalues(). The @@ -185,9 +195,10 @@ template<typename _MatrixType> class EigenSolver * * \returns Const reference to matrix whose columns are the pseudo-eigenvectors. * - * \pre Either the constructor EigenSolver(const MatrixType&) or - * the member function compute(const MatrixType&) has been called - * before. + * \pre Either the constructor + * EigenSolver(const MatrixType&,bool) or the member function + * compute(const MatrixType&, bool) has been called before, and + * \p computeEigenvectors was set to true (the default). * * The real matrix \f$ V \f$ returned by this function and the * block-diagonal matrix \f$ D \f$ returned by pseudoEigenvalueMatrix() @@ -201,6 +212,7 @@ template<typename _MatrixType> class EigenSolver const MatrixType& pseudoEigenvectors() const { ei_assert(m_isInitialized && "EigenSolver is not initialized."); + ei_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues."); return m_eivec; } @@ -208,8 +220,9 @@ template<typename _MatrixType> class EigenSolver * * \returns A block-diagonal matrix. * - * \pre Either the constructor EigenSolver(const MatrixType&) or the - * member function compute(const MatrixType&) has been called before. + * \pre Either the constructor + * EigenSolver(const MatrixType&,bool) or the member function + * compute(const MatrixType&, bool) has been called before. * * The matrix \f$ D \f$ returned by this function is real and * block-diagonal. The blocks on the diagonal are either 1-by-1 or 2-by-2 @@ -226,8 +239,9 @@ template<typename _MatrixType> class EigenSolver * * \returns A const reference to the column vector containing the eigenvalues. * - * \pre Either the constructor EigenSolver(const MatrixType&) or the - * member function compute(const MatrixType&) has been called before. + * \pre Either the constructor + * EigenSolver(const MatrixType&,bool) or the member function + * compute(const MatrixType&, bool) has been called before. * * The eigenvalues are repeated according to their algebraic multiplicity, * so there are as many eigenvalues as rows in the matrix. @@ -247,34 +261,46 @@ template<typename _MatrixType> class EigenSolver /** \brief Computes eigendecomposition of given matrix. * * \param[in] matrix Square matrix whose eigendecomposition is to be computed. + * \param[in] computeEigenvectors If true, both the eigenvectors and the + * eigenvalues are computed; if false, only the eigenvalues are + * computed. * \returns Reference to \c *this * - * This function computes the eigenvalues and eigenvectors of \p matrix. - * The eigenvalues() and eigenvectors() functions can be used to retrieve - * the computed eigendecomposition. + * This function computes the eigenvalues of the real matrix \p matrix. + * The eigenvalues() function can be used to retrieve them. If + * \p computeEigenvectors is true, then the eigenvectors are also computed + * and can be retrieved by calling eigenvectors(). * * The matrix is first reduced to real Schur form using the RealSchur * class. The Schur decomposition is then used to compute the eigenvalues * and eigenvectors. * - * The cost of the computation is dominated by the cost of the Schur - * decomposition, which is very approximately \f$ 25n^3 \f$ where - * \f$ n \f$ is the size of the matrix. + * The cost of the computation is dominated by the cost of the + * Schur decomposition, which is very approximately \f$ 25n^3 \f$ + * (where \f$ n \f$ is the size of the matrix) if \p computeEigenvectors + * is true, and \f$ 10n^3 \f$ if \p computeEigenvectors is false. * * This method reuses of the allocated data in the EigenSolver object. * * Example: \include EigenSolver_compute.cpp * Output: \verbinclude EigenSolver_compute.out */ - EigenSolver& compute(const MatrixType& matrix); + EigenSolver& compute(const MatrixType& matrix, bool computeEigenvectors = true); + + ComputationInfo info() const + { + ei_assert(m_isInitialized && "ComplexEigenSolver is not initialized."); + return m_realSchur.info(); + } private: - void computeEigenvectors(); + void doComputeEigenvectors(); protected: MatrixType m_eivec; EigenvalueType m_eivalues; bool m_isInitialized; + bool m_eigenvectorsOk; RealSchur<MatrixType> m_realSchur; MatrixType m_matT; @@ -286,7 +312,7 @@ template<typename MatrixType> MatrixType EigenSolver<MatrixType>::pseudoEigenvalueMatrix() const { ei_assert(m_isInitialized && "EigenSolver is not initialized."); - Index n = m_eivec.cols(); + Index n = m_eivalues.rows(); MatrixType matD = MatrixType::Zero(n,n); for (Index i=0; i<n; ++i) { @@ -306,6 +332,7 @@ template<typename MatrixType> typename EigenSolver<MatrixType>::EigenvectorsType EigenSolver<MatrixType>::eigenvectors() const { ei_assert(m_isInitialized && "EigenSolver is not initialized."); + ei_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues."); Index n = m_eivec.cols(); EigenvectorsType matV(n,n); for (Index j=0; j<n; ++j) @@ -332,39 +359,46 @@ typename EigenSolver<MatrixType>::EigenvectorsType EigenSolver<MatrixType>::eige } template<typename MatrixType> -EigenSolver<MatrixType>& EigenSolver<MatrixType>::compute(const MatrixType& matrix) +EigenSolver<MatrixType>& EigenSolver<MatrixType>::compute(const MatrixType& matrix, bool computeEigenvectors) { assert(matrix.cols() == matrix.rows()); // Reduce to real Schur form. - m_realSchur.compute(matrix); - m_matT = m_realSchur.matrixT(); - m_eivec = m_realSchur.matrixU(); - - // Compute eigenvalues from matT - m_eivalues.resize(matrix.cols()); - Index i = 0; - while (i < matrix.cols()) + m_realSchur.compute(matrix, computeEigenvectors); + if (m_realSchur.info() == Success) { - if (i == matrix.cols() - 1 || m_matT.coeff(i+1, i) == Scalar(0)) - { - m_eivalues.coeffRef(i) = m_matT.coeff(i, i); - ++i; - } - else + m_matT = m_realSchur.matrixT(); + if (computeEigenvectors) + m_eivec = m_realSchur.matrixU(); + + // Compute eigenvalues from matT + m_eivalues.resize(matrix.cols()); + Index i = 0; + while (i < matrix.cols()) { - Scalar p = Scalar(0.5) * (m_matT.coeff(i, i) - m_matT.coeff(i+1, i+1)); - Scalar z = ei_sqrt(ei_abs(p * p + m_matT.coeff(i+1, i) * m_matT.coeff(i, i+1))); - m_eivalues.coeffRef(i) = ComplexScalar(m_matT.coeff(i+1, i+1) + p, z); - m_eivalues.coeffRef(i+1) = ComplexScalar(m_matT.coeff(i+1, i+1) + p, -z); - i += 2; + if (i == matrix.cols() - 1 || m_matT.coeff(i+1, i) == Scalar(0)) + { + m_eivalues.coeffRef(i) = m_matT.coeff(i, i); + ++i; + } + else + { + Scalar p = Scalar(0.5) * (m_matT.coeff(i, i) - m_matT.coeff(i+1, i+1)); + Scalar z = ei_sqrt(ei_abs(p * p + m_matT.coeff(i+1, i) * m_matT.coeff(i, i+1))); + m_eivalues.coeffRef(i) = ComplexScalar(m_matT.coeff(i+1, i+1) + p, z); + m_eivalues.coeffRef(i+1) = ComplexScalar(m_matT.coeff(i+1, i+1) + p, -z); + i += 2; + } } + + // Compute eigenvectors. + if (computeEigenvectors) + doComputeEigenvectors(); } - - // Compute eigenvectors. - computeEigenvectors(); m_isInitialized = true; + m_eigenvectorsOk = computeEigenvectors; + return *this; } @@ -389,7 +423,7 @@ std::complex<Scalar> cdiv(Scalar xr, Scalar xi, Scalar yr, Scalar yi) template<typename MatrixType> -void EigenSolver<MatrixType>::computeEigenvectors() +void EigenSolver<MatrixType>::doComputeEigenvectors() { const Index size = m_eivec.cols(); const Scalar eps = NumTraits<Scalar>::epsilon(); @@ -404,7 +438,7 @@ void EigenSolver<MatrixType>::computeEigenvectors() // Backsubstitute to find vectors of upper triangular form if (norm == 0.0) { - return; + return; } for (Index n = size-1; n >= 0; n--) diff --git a/Eigen/src/Eigenvalues/EigenvaluesCommon.h b/Eigen/src/Eigenvalues/EigenvaluesCommon.h new file mode 100644 index 000000000..d5fff9ba1 --- /dev/null +++ b/Eigen/src/Eigenvalues/EigenvaluesCommon.h @@ -0,0 +1,39 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk> +// +// Eigen is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 3 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License and a copy of the GNU General Public License along with +// Eigen. If not, see <http://www.gnu.org/licenses/>. + +#ifndef EIGEN_EIGENVALUES_COMMON_H +#define EIGEN_EIGENVALUES_COMMON_H + +/** \eigenvalues_module \ingroup Eigenvalues_Module + * \nonstableyet + * + * \brief Enum for reporting the status of a computation. + */ +enum ComputationInfo { + Success = 0, /**< \brief Computation was successful. */ + NoConvergence = 1 /**< \brief Iterative procedure did not converge. */ +}; + +#endif // EIGEN_EIGENVALUES_COMMON_H + diff --git a/Eigen/src/Eigenvalues/HessenbergDecomposition.h b/Eigen/src/Eigenvalues/HessenbergDecomposition.h index 1111ffb12..783042782 100644 --- a/Eigen/src/Eigenvalues/HessenbergDecomposition.h +++ b/Eigen/src/Eigenvalues/HessenbergDecomposition.h @@ -53,11 +53,11 @@ struct ei_traits<HessenbergDecompositionMatrixHReturnType<MatrixType> > * \f$ Q^{-1} = Q^* \f$). * * Call the function compute() to compute the Hessenberg decomposition of a - * given matrix. Alternatively, you can use the + * given matrix. Alternatively, you can use the * HessenbergDecomposition(const MatrixType&) constructor which computes the * Hessenberg decomposition at construction time. Once the decomposition is * computed, you can use the matrixH() and matrixQ() functions to construct - * the matrices H and Q in the decomposition. + * the matrices H and Q in the decomposition. * * The documentation for matrixH() contains an example of the typical use of * this class. @@ -107,14 +107,15 @@ template<typename _MatrixType> class HessenbergDecomposition */ HessenbergDecomposition(Index size = Size==Dynamic ? 2 : Size) : m_matrix(size,size), - m_temp(size) + m_temp(size), + m_isInitialized(false) { if(size>1) m_hCoeffs.resize(size-1); } - /** \brief Constructor; computes Hessenberg decomposition of given matrix. - * + /** \brief Constructor; computes Hessenberg decomposition of given matrix. + * * \param[in] matrix Square matrix whose Hessenberg decomposition is to be computed. * * This constructor calls compute() to compute the Hessenberg @@ -124,17 +125,23 @@ template<typename _MatrixType> class HessenbergDecomposition */ HessenbergDecomposition(const MatrixType& matrix) : m_matrix(matrix), - m_temp(matrix.rows()) + m_temp(matrix.rows()), + m_isInitialized(false) { if(matrix.rows()<2) + { + m_isInitialized = true; return; + } m_hCoeffs.resize(matrix.rows()-1,1); _compute(m_matrix, m_hCoeffs, m_temp); + m_isInitialized = true; } - /** \brief Computes Hessenberg decomposition of given matrix. - * + /** \brief Computes Hessenberg decomposition of given matrix. + * * \param[in] matrix Square matrix whose Hessenberg decomposition is to be computed. + * \returns Reference to \c *this * * The Hessenberg decomposition is computed by bringing the columns of the * matrix successively in the required form using Householder reflections @@ -148,13 +155,18 @@ template<typename _MatrixType> class HessenbergDecomposition * Example: \include HessenbergDecomposition_compute.cpp * Output: \verbinclude HessenbergDecomposition_compute.out */ - void compute(const MatrixType& matrix) + HessenbergDecomposition& compute(const MatrixType& matrix) { m_matrix = matrix; if(matrix.rows()<2) - return; + { + m_isInitialized = true; + return *this; + } m_hCoeffs.resize(matrix.rows()-1,1); _compute(m_matrix, m_hCoeffs, m_temp); + m_isInitialized = true; + return *this; } /** \brief Returns the Householder coefficients. @@ -165,14 +177,18 @@ template<typename _MatrixType> class HessenbergDecomposition * or the member function compute(const MatrixType&) has been called * before to compute the Hessenberg decomposition of a matrix. * - * The Householder coefficients allow the reconstruction of the matrix + * The Householder coefficients allow the reconstruction of the matrix * \f$ Q \f$ in the Hessenberg decomposition from the packed data. * * \sa packedMatrix(), \ref Householder_Module "Householder module" */ - const CoeffVectorType& householderCoefficients() const { return m_hCoeffs; } + const CoeffVectorType& householderCoefficients() const + { + ei_assert(m_isInitialized && "HessenbergDecomposition is not initialized."); + return m_hCoeffs; + } - /** \brief Returns the internal representation of the decomposition + /** \brief Returns the internal representation of the decomposition * * \returns a const reference to a matrix with the internal representation * of the decomposition. @@ -185,11 +201,11 @@ template<typename _MatrixType> class HessenbergDecomposition * - the upper part and lower sub-diagonal represent the Hessenberg matrix H * - the rest of the lower part contains the Householder vectors that, combined with * Householder coefficients returned by householderCoefficients(), - * allows to reconstruct the matrix Q as + * allows to reconstruct the matrix Q as * \f$ Q = H_{N-1} \ldots H_1 H_0 \f$. - * Here, the matrices \f$ H_i \f$ are the Householder transformations + * Here, the matrices \f$ H_i \f$ are the Householder transformations * \f$ H_i = (I - h_i v_i v_i^T) \f$ - * where \f$ h_i \f$ is the \f$ i \f$th Householder coefficient and + * where \f$ h_i \f$ is the \f$ i \f$th Householder coefficient and * \f$ v_i \f$ is the Householder vector defined by * \f$ v_i = [ 0, \ldots, 0, 1, M(i+2,i), \ldots, M(N-1,i) ]^T \f$ * with M the matrix returned by this function. @@ -201,9 +217,13 @@ template<typename _MatrixType> class HessenbergDecomposition * * \sa householderCoefficients() */ - const MatrixType& packedMatrix() const { return m_matrix; } + const MatrixType& packedMatrix() const + { + ei_assert(m_isInitialized && "HessenbergDecomposition is not initialized."); + return m_matrix; + } - /** \brief Reconstructs the orthogonal matrix Q in the decomposition + /** \brief Reconstructs the orthogonal matrix Q in the decomposition * * \returns object representing the matrix Q * @@ -219,6 +239,7 @@ template<typename _MatrixType> class HessenbergDecomposition */ HouseholderSequenceType matrixQ() const { + ei_assert(m_isInitialized && "HessenbergDecomposition is not initialized."); return HouseholderSequenceType(m_matrix, m_hCoeffs.conjugate(), false, m_matrix.rows() - 1, 1); } @@ -244,6 +265,7 @@ template<typename _MatrixType> class HessenbergDecomposition */ HessenbergDecompositionMatrixHReturnType<MatrixType> matrixH() const { + ei_assert(m_isInitialized && "HessenbergDecomposition is not initialized."); return HessenbergDecompositionMatrixHReturnType<MatrixType>(*this); } @@ -252,15 +274,14 @@ template<typename _MatrixType> class HessenbergDecomposition typedef Matrix<Scalar, 1, Size, Options | RowMajor, 1, MaxSize> VectorType; typedef typename NumTraits<Scalar>::Real RealScalar; static void _compute(MatrixType& matA, CoeffVectorType& hCoeffs, VectorType& temp); - + protected: MatrixType m_matrix; CoeffVectorType m_hCoeffs; VectorType m_temp; + bool m_isInitialized; }; -#ifndef EIGEN_HIDE_HEAVY_CODE - /** \internal * Performs a tridiagonal decomposition of \a matA in place. * @@ -302,8 +323,6 @@ void HessenbergDecomposition<MatrixType>::_compute(MatrixType& matA, CoeffVector } } -#endif // EIGEN_HIDE_HEAVY_CODE - /** \eigenvalues_module \ingroup Eigenvalues_Module * \nonstableyet * diff --git a/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h b/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h index 7b04e6ba7..f27481fe1 100644 --- a/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h +++ b/Eigen/src/Eigenvalues/MatrixBaseEigenvalues.h @@ -37,7 +37,7 @@ struct ei_eigenvalues_selector { typedef typename Derived::PlainObject PlainObject; PlainObject m_eval(m); - return ComplexEigenSolver<PlainObject>(m_eval).eigenvalues(); + return ComplexEigenSolver<PlainObject>(m_eval, false).eigenvalues(); } }; @@ -49,7 +49,7 @@ struct ei_eigenvalues_selector<Derived, false> { typedef typename Derived::PlainObject PlainObject; PlainObject m_eval(m); - return EigenSolver<PlainObject>(m_eval).eigenvalues(); + return EigenSolver<PlainObject>(m_eval, false).eigenvalues(); } }; @@ -101,7 +101,7 @@ SelfAdjointView<MatrixType, UpLo>::eigenvalues() const { typedef typename SelfAdjointView<MatrixType, UpLo>::PlainObject PlainObject; PlainObject thisAsMatrix(*this); - return SelfAdjointEigenSolver<PlainObject>(thisAsMatrix).eigenvalues(); + return SelfAdjointEigenSolver<PlainObject>(thisAsMatrix, false).eigenvalues(); } diff --git a/Eigen/src/Eigenvalues/RealSchur.h b/Eigen/src/Eigenvalues/RealSchur.h index 92ff448ed..156706573 100644 --- a/Eigen/src/Eigenvalues/RealSchur.h +++ b/Eigen/src/Eigenvalues/RealSchur.h @@ -26,6 +26,7 @@ #ifndef EIGEN_REAL_SCHUR_H #define EIGEN_REAL_SCHUR_H +#include "./EigenvaluesCommon.h" #include "./HessenbergDecomposition.h" /** \eigenvalues_module \ingroup Eigenvalues_Module @@ -50,13 +51,13 @@ * the eigendecomposition of a matrix. * * Call the function compute() to compute the real Schur decomposition of a - * given matrix. Alternatively, you can use the RealSchur(const MatrixType&) + * given matrix. Alternatively, you can use the RealSchur(const MatrixType&, bool) * constructor which computes the real Schur decomposition at construction * time. Once the decomposition is computed, you can use the matrixU() and * matrixT() functions to retrieve the matrices U and T in the decomposition. * - * The documentation of RealSchur(const MatrixType&) contains an example of - * the typical use of this class. + * The documentation of RealSchur(const MatrixType&, bool) contains an example + * of the typical use of this class. * * \note The implementation is adapted from * <a href="http://math.nist.gov/javanumerics/jama/">JAMA</a> (public domain). @@ -98,41 +99,46 @@ template<typename _MatrixType> class RealSchur m_matU(size, size), m_workspaceVector(size), m_hess(size), - m_isInitialized(false) + m_isInitialized(false), + m_matUisUptodate(false) { } /** \brief Constructor; computes real Schur decomposition of given matrix. * - * \param[in] matrix Square matrix whose Schur decomposition is to be computed. + * \param[in] matrix Square matrix whose Schur decomposition is to be computed. + * \param[in] computeU If true, both T and U are computed; if false, only T is computed. * * This constructor calls compute() to compute the Schur decomposition. * * Example: \include RealSchur_RealSchur_MatrixType.cpp * Output: \verbinclude RealSchur_RealSchur_MatrixType.out */ - RealSchur(const MatrixType& matrix) + RealSchur(const MatrixType& matrix, bool computeU = true) : m_matT(matrix.rows(),matrix.cols()), m_matU(matrix.rows(),matrix.cols()), m_workspaceVector(matrix.rows()), m_hess(matrix.rows()), - m_isInitialized(false) + m_isInitialized(false), + m_matUisUptodate(false) { - compute(matrix); + compute(matrix, computeU); } /** \brief Returns the orthogonal matrix in the Schur decomposition. * * \returns A const reference to the matrix U. * - * \pre Either the constructor RealSchur(const MatrixType&) or the member - * function compute(const MatrixType&) has been called before to compute - * the Schur decomposition of a matrix. + * \pre Either the constructor RealSchur(const MatrixType&, bool) or the + * member function compute(const MatrixType&, bool) has been called before + * to compute the Schur decomposition of a matrix, and \p computeU was set + * to true (the default value). * - * \sa RealSchur(const MatrixType&) for an example + * \sa RealSchur(const MatrixType&, bool) for an example */ const MatrixType& matrixU() const { ei_assert(m_isInitialized && "RealSchur is not initialized."); + ei_assert(m_matUisUptodate && "The matrix U has not been computed during the RealSchur decomposition."); return m_matU; } @@ -140,11 +146,11 @@ template<typename _MatrixType> class RealSchur * * \returns A const reference to the matrix T. * - * \pre Either the constructor RealSchur(const MatrixType&) or the member - * function compute(const MatrixType&) has been called before to compute - * the Schur decomposition of a matrix. + * \pre Either the constructor RealSchur(const MatrixType&, bool) or the + * member function compute(const MatrixType&, bool) has been called before + * to compute the Schur decomposition of a matrix. * - * \sa RealSchur(const MatrixType&) for an example + * \sa RealSchur(const MatrixType&, bool) for an example */ const MatrixType& matrixT() const { @@ -154,19 +160,38 @@ template<typename _MatrixType> class RealSchur /** \brief Computes Schur decomposition of given matrix. * - * \param[in] matrix Square matrix whose Schur decomposition is to be computed. + * \param[in] matrix Square matrix whose Schur decomposition is to be computed. + * \param[in] computeU If true, both T and U are computed; if false, only T is computed. + * \returns Reference to \c *this * * The Schur decomposition is computed by first reducing the matrix to * Hessenberg form using the class HessenbergDecomposition. The Hessenberg * matrix is then reduced to triangular form by performing Francis QR * iterations with implicit double shift. The cost of computing the Schur * decomposition depends on the number of iterations; as a rough guide, it - * may be taken to be \f$25n^3\f$ flops. + * may be taken to be \f$25n^3\f$ flops if \a computeU is true and + * \f$10n^3\f$ flops if \a computeU is false. * * Example: \include RealSchur_compute.cpp * Output: \verbinclude RealSchur_compute.out */ - void compute(const MatrixType& matrix); + RealSchur& compute(const MatrixType& matrix, bool computeU = true); + + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was succesful, \c NoConvergence otherwise. + */ + ComputationInfo info() const + { + ei_assert(m_isInitialized && "RealSchur is not initialized."); + return m_info; + } + + /** \brief Maximum number of iterations. + * + * Maximum number of iterations allowed for an eigenvalue to converge. + */ + static const int m_maxIterations = 40; private: @@ -174,39 +199,41 @@ template<typename _MatrixType> class RealSchur MatrixType m_matU; ColumnVectorType m_workspaceVector; HessenbergDecomposition<MatrixType> m_hess; + ComputationInfo m_info; bool m_isInitialized; + bool m_matUisUptodate; typedef Matrix<Scalar,3,1> Vector3s; Scalar computeNormOfT(); Index findSmallSubdiagEntry(Index iu, Scalar norm); - void splitOffTwoRows(Index iu, Scalar exshift); + void splitOffTwoRows(Index iu, bool computeU, Scalar exshift); void computeShift(Index iu, Index iter, Scalar& exshift, Vector3s& shiftInfo); void initFrancisQRStep(Index il, Index iu, const Vector3s& shiftInfo, Index& im, Vector3s& firstHouseholderVector); - void performFrancisQRStep(Index il, Index im, Index iu, const Vector3s& firstHouseholderVector, Scalar* workspace); + void performFrancisQRStep(Index il, Index im, Index iu, bool computeU, const Vector3s& firstHouseholderVector, Scalar* workspace); }; template<typename MatrixType> -void RealSchur<MatrixType>::compute(const MatrixType& matrix) +RealSchur<MatrixType>& RealSchur<MatrixType>::compute(const MatrixType& matrix, bool computeU) { assert(matrix.cols() == matrix.rows()); // Step 1. Reduce to Hessenberg form - // TODO skip Q if skipU = true m_hess.compute(matrix); m_matT = m_hess.matrixH(); - m_matU = m_hess.matrixQ(); + if (computeU) + m_matU = m_hess.matrixQ(); // Step 2. Reduce to real Schur form - m_workspaceVector.resize(m_matU.cols()); + m_workspaceVector.resize(m_matT.cols()); Scalar* workspace = &m_workspaceVector.coeffRef(0); // The matrix m_matT is divided in three parts. // Rows 0,...,il-1 are decoupled from the rest because m_matT(il,il-1) is zero. // Rows il,...,iu is the part we are working on (the active window). // Rows iu+1,...,end are already brought in triangular form. - Index iu = m_matU.cols() - 1; + Index iu = m_matT.cols() - 1; Index iter = 0; // iteration count Scalar exshift = 0.0; // sum of exceptional shifts Scalar norm = computeNormOfT(); @@ -226,7 +253,7 @@ void RealSchur<MatrixType>::compute(const MatrixType& matrix) } else if (il == iu-1) // Two roots found { - splitOffTwoRows(iu, exshift); + splitOffTwoRows(iu, computeU, exshift); iu -= 2; iter = 0; } @@ -234,21 +261,29 @@ void RealSchur<MatrixType>::compute(const MatrixType& matrix) { Vector3s firstHouseholderVector, shiftInfo; computeShift(iu, iter, exshift, shiftInfo); - iter = iter + 1; // (Could check iteration count here.) + iter = iter + 1; + if (iter > m_maxIterations) break; Index im; initFrancisQRStep(il, iu, shiftInfo, im, firstHouseholderVector); - performFrancisQRStep(il, im, iu, firstHouseholderVector, workspace); + performFrancisQRStep(il, im, iu, computeU, firstHouseholderVector, workspace); } } + if(iter <= m_maxIterations) + m_info = Success; + else + m_info = NoConvergence; + m_isInitialized = true; + m_matUisUptodate = computeU; + return *this; } /** \internal Computes and returns vector L1 norm of T */ template<typename MatrixType> inline typename MatrixType::Scalar RealSchur<MatrixType>::computeNormOfT() { - const Index size = m_matU.cols(); + const Index size = m_matT.cols(); // FIXME to be efficient the following would requires a triangular reduxion code // Scalar norm = m_matT.upper().cwiseAbs().sum() // + m_matT.bottomLeftCorner(size-1,size-1).diagonal().cwiseAbs().sum(); @@ -277,9 +312,9 @@ inline typename MatrixType::Index RealSchur<MatrixType>::findSmallSubdiagEntry(I /** \internal Update T given that rows iu-1 and iu decouple from the rest. */ template<typename MatrixType> -inline void RealSchur<MatrixType>::splitOffTwoRows(Index iu, Scalar exshift) +inline void RealSchur<MatrixType>::splitOffTwoRows(Index iu, bool computeU, Scalar exshift) { - const Index size = m_matU.cols(); + const Index size = m_matT.cols(); // The eigenvalues of the 2x2 matrix [a b; c d] are // trace +/- sqrt(discr/4) where discr = tr^2 - 4*det, tr = a + d, det = ad - bc @@ -300,7 +335,8 @@ inline void RealSchur<MatrixType>::splitOffTwoRows(Index iu, Scalar exshift) m_matT.rightCols(size-iu+1).applyOnTheLeft(iu-1, iu, rot.adjoint()); m_matT.topRows(iu+1).applyOnTheRight(iu-1, iu, rot); m_matT.coeffRef(iu, iu-1) = Scalar(0); - m_matU.applyOnTheRight(iu-1, iu, rot); + if (computeU) + m_matU.applyOnTheRight(iu-1, iu, rot); } if (iu > 1) @@ -375,12 +411,12 @@ inline void RealSchur<MatrixType>::initFrancisQRStep(Index il, Index iu, const V /** \internal Perform a Francis QR step involving rows il:iu and columns im:iu. */ template<typename MatrixType> -inline void RealSchur<MatrixType>::performFrancisQRStep(Index il, Index im, Index iu, const Vector3s& firstHouseholderVector, Scalar* workspace) +inline void RealSchur<MatrixType>::performFrancisQRStep(Index il, Index im, Index iu, bool computeU, const Vector3s& firstHouseholderVector, Scalar* workspace) { assert(im >= il); assert(im <= iu-2); - const Index size = m_matU.cols(); + const Index size = m_matT.cols(); for (Index k = im; k <= iu-2; ++k) { @@ -406,7 +442,8 @@ inline void RealSchur<MatrixType>::performFrancisQRStep(Index il, Index im, Inde // These Householder transformations form the O(n^3) part of the algorithm m_matT.block(k, k, 3, size-k).applyHouseholderOnTheLeft(ess, tau, workspace); m_matT.block(0, k, std::min(iu,k+3) + 1, 3).applyHouseholderOnTheRight(ess, tau, workspace); - m_matU.block(0, k, size, 3).applyHouseholderOnTheRight(ess, tau, workspace); + if (computeU) + m_matU.block(0, k, size, 3).applyHouseholderOnTheRight(ess, tau, workspace); } } @@ -420,7 +457,8 @@ inline void RealSchur<MatrixType>::performFrancisQRStep(Index il, Index im, Inde m_matT.coeffRef(iu-1, iu-2) = beta; m_matT.block(iu-1, iu-1, 2, size-iu+1).applyHouseholderOnTheLeft(ess, tau, workspace); m_matT.block(0, iu-1, iu+1, 2).applyHouseholderOnTheRight(ess, tau, workspace); - m_matU.block(0, iu-1, size, 2).applyHouseholderOnTheRight(ess, tau, workspace); + if (computeU) + m_matU.block(0, iu-1, size, 2).applyHouseholderOnTheRight(ess, tau, workspace); } // clean up pollution due to round-off errors diff --git a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h index 2c53655d1..a77b96186 100644 --- a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +++ b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h @@ -26,6 +26,9 @@ #ifndef EIGEN_SELFADJOINTEIGENSOLVER_H #define EIGEN_SELFADJOINTEIGENSOLVER_H +#include "./EigenvaluesCommon.h" +#include "./Tridiagonalization.h" + /** \eigenvalues_module \ingroup Eigenvalues_Module * \nonstableyet * @@ -35,12 +38,12 @@ * * \tparam _MatrixType the type of the matrix of which we are computing the * eigendecomposition; this is expected to be an instantiation of the Matrix - * class template. Currently, only real matrices are supported. + * class template. * * A matrix \f$ A \f$ is selfadjoint if it equals its adjoint. For real * matrices, this means that the matrix is symmetric: it equals its * transpose. This class computes the eigenvalues and eigenvectors of a - * selfadjoint matrix. These are the scalars \f$ \lambda \f$ and vectors + * selfadjoint matrix. These are the scalars \f$ \lambda \f$ and vectors * \f$ v \f$ such that \f$ Av = \lambda v \f$. The eigenvalues of a * selfadjoint matrix are always real. If \f$ D \f$ is a diagonal matrix with * the eigenvalues on the diagonal, and \f$ V \f$ is a matrix with the @@ -52,6 +55,8 @@ * faster and more accurate than the general purpose eigenvalue algorithms * implemented in EigenSolver and ComplexEigenSolver. * + * Only the \b lower \b triangular \b part of the input matrix is referenced. + * * This class can also be used to solve the generalized eigenvalue problem * \f$ Av = \lambda Bv \f$. In this case, the matrix \f$ A \f$ should be * selfadjoint and the matrix \f$ B \f$ should be positive definite. @@ -65,7 +70,7 @@ * * The documentation for SelfAdjointEigenSolver(const MatrixType&, bool) * contains an example of the typical use of this class. - * + * * \sa MatrixBase::eigenvalues(), class EigenSolver, class ComplexEigenSolver */ template<typename _MatrixType> class SelfAdjointEigenSolver @@ -84,15 +89,15 @@ template<typename _MatrixType> class SelfAdjointEigenSolver typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::Index Index; - /** \brief Real scalar type for \p _MatrixType. + /** \brief Real scalar type for \p _MatrixType. * - * This is just \c Scalar if #Scalar is real (e.g., \c float or + * This is just \c Scalar if #Scalar is real (e.g., \c float or * \c double), and the type of the real part of \c Scalar if #Scalar is * complex. */ typedef typename NumTraits<Scalar>::Real RealScalar; - /** \brief Type for vector of eigenvalues as returned by eigenvalues(). + /** \brief Type for vector of eigenvalues as returned by eigenvalues(). * * This is a column vector with entries of type #RealScalar. * The length of the vector is the size of \p _MatrixType. @@ -114,11 +119,9 @@ template<typename _MatrixType> class SelfAdjointEigenSolver SelfAdjointEigenSolver() : m_eivec(), m_eivalues(), - m_tridiag(), - m_subdiag() - { - ei_assert(Size!=Dynamic); - } + m_subdiag(), + m_isInitialized(false) + { } /** \brief Constructor, pre-allocates memory for dynamic-size matrices. * @@ -128,7 +131,7 @@ template<typename _MatrixType> class SelfAdjointEigenSolver * This constructor is useful for dynamic-size matrices, when the user * intends to perform decompositions via compute(const MatrixType&, bool) * or compute(const MatrixType&, const MatrixType&, bool). The \p size - * parameter is only used as a hint. It is not an error to give a wrong + * parameter is only used as a hint. It is not an error to give a wrong * \p size, but it may impair performance. * * \sa compute(const MatrixType&, bool) for an example @@ -136,17 +139,17 @@ template<typename _MatrixType> class SelfAdjointEigenSolver SelfAdjointEigenSolver(Index size) : m_eivec(size, size), m_eivalues(size), - m_tridiag(size), - m_subdiag(size > 1 ? size - 1 : 1) + m_subdiag(size > 1 ? size - 1 : 1), + m_isInitialized(false) {} - /** \brief Constructor; computes eigendecomposition of given matrix. - * + /** \brief Constructor; computes eigendecomposition of given matrix. + * * \param[in] matrix Selfadjoint matrix whose eigendecomposition is to - * be computed. + * be computed. Only the lower triangular part of the matrix is referenced. * \param[in] computeEigenvectors If true, both the eigenvectors and the * eigenvalues are computed; if false, only the eigenvalues are - * computed. + * computed. * * This constructor calls compute(const MatrixType&, bool) to compute the * eigenvalues of the matrix \p matrix. The eigenvectors are computed if @@ -155,55 +158,58 @@ template<typename _MatrixType> class SelfAdjointEigenSolver * Example: \include SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType.cpp * Output: \verbinclude SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType.out * - * \sa compute(const MatrixType&, bool), + * \sa compute(const MatrixType&, bool), * SelfAdjointEigenSolver(const MatrixType&, const MatrixType&, bool) */ SelfAdjointEigenSolver(const MatrixType& matrix, bool computeEigenvectors = true) : m_eivec(matrix.rows(), matrix.cols()), m_eivalues(matrix.cols()), - m_tridiag(matrix.rows()), - m_subdiag(matrix.rows() > 1 ? matrix.rows() - 1 : 1) + m_subdiag(matrix.rows() > 1 ? matrix.rows() - 1 : 1), + m_isInitialized(false) { compute(matrix, computeEigenvectors); } - /** \brief Constructor; computes eigendecomposition of given matrix pencil. - * + /** \brief Constructor; computes generalized eigendecomposition of given matrix pencil. + * * \param[in] matA Selfadjoint matrix in matrix pencil. + * Only the lower triangular part of the matrix is referenced. * \param[in] matB Positive-definite matrix in matrix pencil. + * Only the lower triangular part of the matrix is referenced. * \param[in] computeEigenvectors If true, both the eigenvectors and the * eigenvalues are computed; if false, only the eigenvalues are - * computed. + * computed. * - * This constructor calls compute(const MatrixType&, const MatrixType&, bool) + * This constructor calls compute(const MatrixType&, const MatrixType&, bool) * to compute the eigenvalues and (if requested) the eigenvectors of the * generalized eigenproblem \f$ Ax = \lambda B x \f$ with \a matA the * selfadjoint matrix \f$ A \f$ and \a matB the positive definite matrix - * \f$ B \f$ . The eigenvectors are computed if \a computeEigenvectors is - * true. + * \f$ B \f$. Each eigenvector \f$ x \f$ satisfies the property + * \f$ x^* B x = 1 \f$. The eigenvectors are computed if + * \a computeEigenvectors is true. * * Example: \include SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType2.cpp * Output: \verbinclude SelfAdjointEigenSolver_SelfAdjointEigenSolver_MatrixType2.out * - * \sa compute(const MatrixType&, const MatrixType&, bool), + * \sa compute(const MatrixType&, const MatrixType&, bool), * SelfAdjointEigenSolver(const MatrixType&, bool) */ SelfAdjointEigenSolver(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors = true) : m_eivec(matA.rows(), matA.cols()), m_eivalues(matA.cols()), - m_tridiag(matA.rows()), - m_subdiag(matA.rows() > 1 ? matA.rows() - 1 : 1) + m_subdiag(matA.rows() > 1 ? matA.rows() - 1 : 1), + m_isInitialized(false) { compute(matA, matB, computeEigenvectors); } - /** \brief Computes eigendecomposition of given matrix. - * + /** \brief Computes eigendecomposition of given matrix. + * * \param[in] matrix Selfadjoint matrix whose eigendecomposition is to - * be computed. + * be computed. Only the lower triangular part of the matrix is referenced. * \param[in] computeEigenvectors If true, both the eigenvectors and the * eigenvalues are computed; if false, only the eigenvalues are - * computed. + * computed. * \returns Reference to \c *this * * This function computes the eigenvalues of \p matrix. The eigenvalues() @@ -231,28 +237,33 @@ template<typename _MatrixType> class SelfAdjointEigenSolver */ SelfAdjointEigenSolver& compute(const MatrixType& matrix, bool computeEigenvectors = true); - /** \brief Computes eigendecomposition of given matrix pencil. - * + /** \brief Computes generalized eigendecomposition of given matrix pencil. + * * \param[in] matA Selfadjoint matrix in matrix pencil. + * Only the lower triangular part of the matrix is referenced. * \param[in] matB Positive-definite matrix in matrix pencil. + * Only the lower triangular part of the matrix is referenced. * \param[in] computeEigenvectors If true, both the eigenvectors and the * eigenvalues are computed; if false, only the eigenvalues are - * computed. + * computed. * \returns Reference to \c *this * * This function computes eigenvalues and (if requested) the eigenvectors * of the generalized eigenproblem \f$ Ax = \lambda B x \f$ with \a matA * the selfadjoint matrix \f$ A \f$ and \a matB the positive definite - * matrix \f$ B \f$. The eigenvalues() function can be used to retrieve + * matrix \f$ B \f$. In addition, each eigenvector \f$ x \f$ + * satisfies the property \f$ x^* B x = 1 \f$. + * + * The eigenvalues() function can be used to retrieve * the eigenvalues. If \p computeEigenvectors is true, then the * eigenvectors are also computed and can be retrieved by calling * eigenvectors(). * - * The implementation uses LLT to compute the Cholesky decomposition + * The implementation uses LLT to compute the Cholesky decomposition * \f$ B = LL^* \f$ and calls compute(const MatrixType&, bool) to compute * the eigendecomposition \f$ L^{-1} A (L^*)^{-1} \f$. This solves the * generalized eigenproblem, because any solution of the generalized - * eigenproblem \f$ Ax = \lambda B x \f$ corresponds to a solution + * eigenproblem \f$ Ax = \lambda B x \f$ corresponds to a solution * \f$ L^{-1} A (L^*)^{-1} (L^* x) = \lambda (L^* x) \f$ of the * eigenproblem for \f$ L^{-1} A (L^*)^{-1} \f$. * @@ -263,7 +274,7 @@ template<typename _MatrixType> class SelfAdjointEigenSolver */ SelfAdjointEigenSolver& compute(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors = true); - /** \brief Returns the eigenvectors of given matrix (pencil). + /** \brief Returns the eigenvectors of given matrix (pencil). * * \returns A const reference to the matrix whose columns are the eigenvectors. * @@ -283,13 +294,12 @@ template<typename _MatrixType> class SelfAdjointEigenSolver */ const MatrixType& eigenvectors() const { - #ifndef NDEBUG - ei_assert(m_eigenvectorsOk); - #endif + ei_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized."); + ei_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues."); return m_eivec; } - /** \brief Returns the eigenvalues of given matrix (pencil). + /** \brief Returns the eigenvalues of given matrix (pencil). * * \returns A const reference to the column vector containing the eigenvalues. * @@ -303,9 +313,13 @@ template<typename _MatrixType> class SelfAdjointEigenSolver * * \sa eigenvectors(), MatrixBase::eigenvalues() */ - const RealVectorType& eigenvalues() const { return m_eivalues; } + const RealVectorType& eigenvalues() const + { + ei_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized."); + return m_eivalues; + } - /** \brief Computes the positive-definite square root of the matrix. + /** \brief Computes the positive-definite square root of the matrix. * * \returns the positive-definite square root of the matrix * @@ -320,15 +334,17 @@ template<typename _MatrixType> class SelfAdjointEigenSolver * Example: \include SelfAdjointEigenSolver_operatorSqrt.cpp * Output: \verbinclude SelfAdjointEigenSolver_operatorSqrt.out * - * \sa operatorInverseSqrt(), + * \sa operatorInverseSqrt(), * \ref MatrixFunctions_Module "MatrixFunctions Module" */ MatrixType operatorSqrt() const { + ei_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized."); + ei_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues."); return m_eivec * m_eivalues.cwiseSqrt().asDiagonal() * m_eivec.adjoint(); } - /** \brief Computes the inverse square root of the matrix. + /** \brief Computes the inverse square root of the matrix. * * \returns the inverse positive-definite square root of the matrix * @@ -348,22 +364,36 @@ template<typename _MatrixType> class SelfAdjointEigenSolver */ MatrixType operatorInverseSqrt() const { + ei_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized."); + ei_assert(m_eigenvectorsOk && "The eigenvectors have not been computed together with the eigenvalues."); return m_eivec * m_eivalues.cwiseInverse().cwiseSqrt().asDiagonal() * m_eivec.adjoint(); } + /** \brief Reports whether previous computation was successful. + * + * \returns \c Success if computation was succesful, \c NoConvergence otherwise. + */ + ComputationInfo info() const + { + ei_assert(m_isInitialized && "SelfAdjointEigenSolver is not initialized."); + return m_info; + } + + /** \brief Maximum number of iterations. + * + * Maximum number of iterations allowed for an eigenvalue to converge. + */ + static const int m_maxIterations = 30; protected: MatrixType m_eivec; RealVectorType m_eivalues; - TridiagonalizationType m_tridiag; typename TridiagonalizationType::SubDiagonalType m_subdiag; - #ifndef NDEBUG + ComputationInfo m_info; + bool m_isInitialized; bool m_eigenvectorsOk; - #endif }; -#ifndef EIGEN_HIDE_HEAVY_CODE - /** \internal * * \eigenvalues_module \ingroup Eigenvalues_Module @@ -386,30 +416,33 @@ static void ei_tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index template<typename MatrixType> SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType>::compute(const MatrixType& matrix, bool computeEigenvectors) { - #ifndef NDEBUG - m_eigenvectorsOk = computeEigenvectors; - #endif assert(matrix.cols() == matrix.rows()); Index n = matrix.cols(); m_eivalues.resize(n,1); - m_eivec.resize(n,n); if(n==1) { m_eivalues.coeffRef(0,0) = ei_real(matrix.coeff(0,0)); - m_eivec.setOnes(); + if(computeEigenvectors) + m_eivec.setOnes(); + m_info = Success; + m_isInitialized = true; + m_eigenvectorsOk = computeEigenvectors; return *this; } - m_tridiag.compute(matrix); + // declare some aliases RealVectorType& diag = m_eivalues; - diag = m_tridiag.diagonal(); - m_subdiag = m_tridiag.subDiagonal(); - if (computeEigenvectors) - m_eivec = m_tridiag.matrixQ(); + MatrixType& mat = m_eivec; + + mat = matrix; + m_subdiag.resize(n-1); + ei_tridiagonalization_inplace(mat, diag, m_subdiag, computeEigenvectors); Index end = n-1; Index start = 0; + Index iter = 0; // number of iterations we are working on one element + while (end>0) { for (Index i = start; i<end; ++i) @@ -418,9 +451,17 @@ SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType>::compute( // find the largest unreduced block while (end>0 && m_subdiag[end-1]==0) + { + iter = 0; end--; + } if (end<=0) break; + + // if we spent too many iterations on the current element, we give up + iter++; + if(iter > m_maxIterations) break; + start = end - 1; while (start>0 && m_subdiag[start-1]!=0) start--; @@ -428,19 +469,31 @@ SelfAdjointEigenSolver<MatrixType>& SelfAdjointEigenSolver<MatrixType>::compute( ei_tridiagonal_qr_step(diag.data(), m_subdiag.data(), start, end, computeEigenvectors ? m_eivec.data() : (Scalar*)0, n); } + if (iter <= m_maxIterations) + m_info = Success; + else + m_info = NoConvergence; + // Sort eigenvalues and corresponding vectors. // TODO make the sort optional ? // TODO use a better sort algorithm !! - for (Index i = 0; i < n-1; ++i) + if (m_info == Success) { - Index k; - m_eivalues.segment(i,n-i).minCoeff(&k); - if (k > 0) + for (Index i = 0; i < n-1; ++i) { - std::swap(m_eivalues[i], m_eivalues[k+i]); - m_eivec.col(i).swap(m_eivec.col(k+i)); + Index k; + m_eivalues.segment(i,n-i).minCoeff(&k); + if (k > 0) + { + std::swap(m_eivalues[i], m_eivalues[k+i]); + if(computeEigenvectors) + m_eivec.col(i).swap(m_eivec.col(k+i)); + } } } + + m_isInitialized = true; + m_eigenvectorsOk = computeEigenvectors; return *this; } @@ -450,39 +503,23 @@ compute(const MatrixType& matA, const MatrixType& matB, bool computeEigenvectors { ei_assert(matA.cols()==matA.rows() && matB.rows()==matA.rows() && matB.cols()==matB.rows()); - // Compute the cholesky decomposition of matB = L L' + // Compute the cholesky decomposition of matB = L L' = U'U LLT<MatrixType> cholB(matB); // compute C = inv(L) A inv(L') - MatrixType matC = matA; - cholB.matrixL().solveInPlace(matC); - // FIXME since we currently do not support A * inv(L'), let's do (inv(L) A')' : - matC.adjointInPlace(); - cholB.matrixL().solveInPlace(matC); - matC.adjointInPlace(); - // this version works too: -// matC = matC.transpose(); -// cholB.matrixL().conjugate().template marked<Lower>().solveTriangularInPlace(matC); -// matC = matC.transpose(); - // FIXME: this should work: (currently it only does for small matrices) -// Transpose<MatrixType> trMatC(matC); -// cholB.matrixL().conjugate().eval().template marked<Lower>().solveTriangularInPlace(trMatC); + MatrixType matC = matA.template selfadjointView<Lower>(); + cholB.matrixL().template solveInPlace<OnTheLeft>(matC); + cholB.matrixU().template solveInPlace<OnTheRight>(matC); compute(matC, computeEigenvectors); - if (computeEigenvectors) - { - // transform back the eigen vectors: evecs = inv(U) * evecs + // transform back the eigen vectors: evecs = inv(U) * evecs + if(computeEigenvectors) cholB.matrixU().solveInPlace(m_eivec); - for (Index i=0; i<m_eivec.cols(); ++i) - m_eivec.col(i) = m_eivec.col(i).normalized(); - } + return *this; } -#endif // EIGEN_HIDE_HEAVY_CODE - -#ifndef EIGEN_EXTERN_INSTANTIATIONS template<typename RealScalar, typename Scalar, typename Index> static void ei_tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index start, Index end, Scalar* matrixQ, Index n) { @@ -524,6 +561,5 @@ static void ei_tridiagonal_qr_step(RealScalar* diag, RealScalar* subdiag, Index } } } -#endif #endif // EIGEN_SELFADJOINTEIGENSOLVER_H diff --git a/Eigen/src/Eigenvalues/Tridiagonalization.h b/Eigen/src/Eigenvalues/Tridiagonalization.h index 02917f2e6..af970e94d 100644 --- a/Eigen/src/Eigenvalues/Tridiagonalization.h +++ b/Eigen/src/Eigenvalues/Tridiagonalization.h @@ -80,7 +80,7 @@ template<typename _MatrixType> class Tridiagonalization typedef Matrix<Scalar, SizeMinusOne, 1, Options & ~RowMajor, MaxSizeMinusOne, 1> CoeffVectorType; typedef typename ei_plain_col_type<MatrixType, RealScalar>::type DiagonalType; typedef Matrix<RealScalar, SizeMinusOne, 1, Options & ~RowMajor, MaxSizeMinusOne, 1> SubDiagonalType; - + typedef typename ei_meta_if<NumTraits<Scalar>::IsComplex, typename Diagonal<MatrixType,0>::RealReturnType, Diagonal<MatrixType,0> @@ -109,11 +109,13 @@ template<typename _MatrixType> class Tridiagonalization * \sa compute() for an example. */ Tridiagonalization(Index size = Size==Dynamic ? 2 : Size) - : m_matrix(size,size), m_hCoeffs(size > 1 ? size-1 : 1) + : m_matrix(size,size), + m_hCoeffs(size > 1 ? size-1 : 1), + m_isInitialized(false) {} - /** \brief Constructor; computes tridiagonal decomposition of given matrix. - * + /** \brief Constructor; computes tridiagonal decomposition of given matrix. + * * \param[in] matrix Selfadjoint matrix whose tridiagonal decomposition * is to be computed. * @@ -123,15 +125,19 @@ template<typename _MatrixType> class Tridiagonalization * Output: \verbinclude Tridiagonalization_Tridiagonalization_MatrixType.out */ Tridiagonalization(const MatrixType& matrix) - : m_matrix(matrix), m_hCoeffs(matrix.cols() > 1 ? matrix.cols()-1 : 1) + : m_matrix(matrix), + m_hCoeffs(matrix.cols() > 1 ? matrix.cols()-1 : 1), + m_isInitialized(false) { _compute(m_matrix, m_hCoeffs); + m_isInitialized = true; } - /** \brief Computes tridiagonal decomposition of given matrix. - * + /** \brief Computes tridiagonal decomposition of given matrix. + * * \param[in] matrix Selfadjoint matrix whose tridiagonal decomposition * is to be computed. + * \returns Reference to \c *this * * The tridiagonal decomposition is computed by bringing the columns of * the matrix successively in the required form using Householder @@ -144,11 +150,13 @@ template<typename _MatrixType> class Tridiagonalization * Example: \include Tridiagonalization_compute.cpp * Output: \verbinclude Tridiagonalization_compute.out */ - void compute(const MatrixType& matrix) + Tridiagonalization& compute(const MatrixType& matrix) { m_matrix = matrix; m_hCoeffs.resize(matrix.rows()-1, 1); - _compute(m_matrix, m_hCoeffs); + ei_tridiagonalization_inplace(m_matrix, m_hCoeffs); + m_isInitialized = true; + return *this; } /** \brief Returns the Householder coefficients. @@ -159,7 +167,7 @@ template<typename _MatrixType> class Tridiagonalization * the member function compute(const MatrixType&) has been called before * to compute the tridiagonal decomposition of a matrix. * - * The Householder coefficients allow the reconstruction of the matrix + * The Householder coefficients allow the reconstruction of the matrix * \f$ Q \f$ in the tridiagonal decomposition from the packed data. * * Example: \include Tridiagonalization_householderCoefficients.cpp @@ -167,9 +175,13 @@ template<typename _MatrixType> class Tridiagonalization * * \sa packedMatrix(), \ref Householder_Module "Householder module" */ - inline CoeffVectorType householderCoefficients() const { return m_hCoeffs; } + inline CoeffVectorType householderCoefficients() const + { + ei_assert(m_isInitialized && "Tridiagonalization is not initialized."); + return m_hCoeffs; + } - /** \brief Returns the internal representation of the decomposition + /** \brief Returns the internal representation of the decomposition * * \returns a const reference to a matrix with the internal representation * of the decomposition. @@ -181,14 +193,14 @@ template<typename _MatrixType> class Tridiagonalization * The returned matrix contains the following information: * - the strict upper triangular part is equal to the input matrix A. * - the diagonal and lower sub-diagonal represent the real tridiagonal - * symmetric matrix T. + * symmetric matrix T. * - the rest of the lower part contains the Householder vectors that, * combined with Householder coefficients returned by * householderCoefficients(), allows to reconstruct the matrix Q as * \f$ Q = H_{N-1} \ldots H_1 H_0 \f$. - * Here, the matrices \f$ H_i \f$ are the Householder transformations + * Here, the matrices \f$ H_i \f$ are the Householder transformations * \f$ H_i = (I - h_i v_i v_i^T) \f$ - * where \f$ h_i \f$ is the \f$ i \f$th Householder coefficient and + * where \f$ h_i \f$ is the \f$ i \f$th Householder coefficient and * \f$ v_i \f$ is the Householder vector defined by * \f$ v_i = [ 0, \ldots, 0, 1, M(i+2,i), \ldots, M(N-1,i) ]^T \f$ * with M the matrix returned by this function. @@ -200,9 +212,13 @@ template<typename _MatrixType> class Tridiagonalization * * \sa householderCoefficients() */ - inline const MatrixType& packedMatrix() const { return m_matrix; } + inline const MatrixType& packedMatrix() const + { + ei_assert(m_isInitialized && "Tridiagonalization is not initialized."); + return m_matrix; + } - /** \brief Returns the unitary matrix Q in the decomposition + /** \brief Returns the unitary matrix Q in the decomposition * * \returns object representing the matrix Q * @@ -219,6 +235,7 @@ template<typename _MatrixType> class Tridiagonalization */ HouseholderSequenceType matrixQ() const { + ei_assert(m_isInitialized && "Tridiagonalization is not initialized."); return HouseholderSequenceType(m_matrix, m_hCoeffs.conjugate(), false, m_matrix.rows() - 1, 1); } @@ -268,43 +285,6 @@ template<typename _MatrixType> class Tridiagonalization */ const SubDiagonalReturnType subDiagonal() const; - /** \brief Performs a full decomposition in place - * - * \param[in,out] mat On input, the selfadjoint matrix whose tridiagonal - * decomposition is to be computed. On output, the orthogonal matrix Q - * in the decomposition if \p extractQ is true. - * \param[out] diag The diagonal of the tridiagonal matrix T in the - * decomposition. - * \param[out] subdiag The subdiagonal of the tridiagonal matrix T in - * the decomposition. - * \param[in] extractQ If true, the orthogonal matrix Q in the - * decomposition is computed and stored in \p mat. - * - * Compute the tridiagonal matrix of \p mat in place. The tridiagonal - * matrix T is passed to the output parameters \p diag and \p subdiag. If - * \p extractQ is true, then the orthogonal matrix Q is passed to \p mat. - * - * The vectors \p diag and \p subdiag are not resized. The function - * assumes that they are already of the correct size. The length of the - * vector \p diag should equal the number of rows in \p mat, and the - * length of the vector \p subdiag should be one left. - * - * This implementation contains an optimized path for real 3-by-3 matrices - * which is especially useful for plane fitting. - * - * \note Notwithstanding the name, the current implementation copies - * \p mat to a temporary matrix and uses that matrix to compute the - * decomposition. - * - * Example (this uses the same matrix as the example in - * Tridiagonalization(const MatrixType&)): - * \include Tridiagonalization_decomposeInPlace.cpp - * Output: \verbinclude Tridiagonalization_decomposeInPlace.out - * - * \sa Tridiagonalization(const MatrixType&), compute() - */ - static void decomposeInPlace(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ = true); - protected: static void _compute(MatrixType& matA, CoeffVectorType& hCoeffs); @@ -312,12 +292,14 @@ template<typename _MatrixType> class Tridiagonalization MatrixType m_matrix; CoeffVectorType m_hCoeffs; + bool m_isInitialized; }; template<typename MatrixType> const typename Tridiagonalization<MatrixType>::DiagonalReturnType Tridiagonalization<MatrixType>::diagonal() const { + ei_assert(m_isInitialized && "Tridiagonalization is not initialized."); return m_matrix.diagonal(); } @@ -325,6 +307,7 @@ template<typename MatrixType> const typename Tridiagonalization<MatrixType>::SubDiagonalReturnType Tridiagonalization<MatrixType>::subDiagonal() const { + ei_assert(m_isInitialized && "Tridiagonalization is not initialized."); Index n = m_matrix.rows(); return Block<MatrixType,SizeMinusOne,SizeMinusOne>(m_matrix, 1, 0, n-1,n-1).diagonal(); } @@ -335,6 +318,7 @@ Tridiagonalization<MatrixType>::matrixT() const { // FIXME should this function (and other similar ones) rather take a matrix as argument // and fill it ? (to avoid temporaries) + ei_assert(m_isInitialized && "Tridiagonalization is not initialized."); Index n = m_matrix.rows(); MatrixType matT = m_matrix; matT.topRightCorner(n-1, n-1).diagonal() = subDiagonal().template cast<Scalar>().conjugate(); @@ -346,24 +330,37 @@ Tridiagonalization<MatrixType>::matrixT() const return matT; } -#ifndef EIGEN_HIDE_HEAVY_CODE - /** \internal - * Performs a tridiagonal decomposition of \a matA in place. + * Performs a tridiagonal decomposition of the selfadjoint matrix \a matA in-place. * - * \param matA the input selfadjoint matrix - * \param hCoeffs returned Householder coefficients + * \param[in,out] matA On input the selfadjoint matrix. Only the \b lower triangular part is referenced. + * On output, the strict upper part is left unchanged, and the lower triangular part + * represents the T and Q matrices in packed format has detailed below. + * \param[out] hCoeffs returned Householder coefficients (see below) * - * The result is written in the lower triangular part of \a matA. + * On output, the tridiagonal selfadjoint matrix T is stored in the diagonal + * and lower sub-diagonal of the matrix \a matA. + * The unitary matrix Q is represented in a compact way as a product of + * Householder reflectors \f$ H_i \f$ such that: + * \f$ Q = H_{N-1} \ldots H_1 H_0 \f$. + * The Householder reflectors are defined as + * \f$ H_i = (I - h_i v_i v_i^T) \f$ + * where \f$ h_i = hCoeffs[i]\f$ is the \f$ i \f$th Householder coefficient and + * \f$ v_i \f$ is the Householder vector defined by + * \f$ v_i = [ 0, \ldots, 0, 1, matA(i+2,i), \ldots, matA(N-1,i) ]^T \f$. * * Implemented from Golub's "Matrix Computations", algorithm 8.3.1. * - * \sa packedMatrix() + * \sa Tridiagonalization::packedMatrix() */ -template<typename MatrixType> -void Tridiagonalization<MatrixType>::_compute(MatrixType& matA, CoeffVectorType& hCoeffs) +template<typename MatrixType, typename CoeffVectorType> +void ei_tridiagonalization_inplace(MatrixType& matA, CoeffVectorType& hCoeffs) { - assert(matA.rows()==matA.cols()); + ei_assert(matA.rows()==matA.cols()); + ei_assert(matA.rows()==hCoeffs.size()+1); + typedef typename MatrixType::Index Index; + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; Index n = matA.rows(); for (Index i = 0; i<n-1; ++i) { @@ -389,69 +386,139 @@ void Tridiagonalization<MatrixType>::_compute(MatrixType& matA, CoeffVectorType& } } -template<typename MatrixType> -void Tridiagonalization<MatrixType>::decomposeInPlace(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ) +// forward declaration, implementation at the end of this file +template<typename MatrixType, int Size=MatrixType::ColsAtCompileTime> +struct ei_tridiagonalization_inplace_selector; + +/** \brief Performs a full tridiagonalization in place + * + * \param[in,out] mat On input, the selfadjoint matrix whose tridiagonal + * decomposition is to be computed. Only the lower triangular part referenced. + * The rest is left unchanged. On output, the orthogonal matrix Q + * in the decomposition if \p extractQ is true. + * \param[out] diag The diagonal of the tridiagonal matrix T in the + * decomposition. + * \param[out] subdiag The subdiagonal of the tridiagonal matrix T in + * the decomposition. + * \param[in] extractQ If true, the orthogonal matrix Q in the + * decomposition is computed and stored in \p mat. + * + * Computes the tridiagonal decomposition of the selfadjoint matrix \p mat in place + * such that \f$ mat = Q T Q^* \f$ where \f$ Q \f$ is unitary and \f$ T \f$ a real + * symmetric tridiagonal matrix. + * + * The tridiagonal matrix T is passed to the output parameters \p diag and \p subdiag. If + * \p extractQ is true, then the orthogonal matrix Q is passed to \p mat. Otherwise the lower + * part of the matrix \p mat is destroyed. + * + * The vectors \p diag and \p subdiag are not resized. The function + * assumes that they are already of the correct size. The length of the + * vector \p diag should equal the number of rows in \p mat, and the + * length of the vector \p subdiag should be one left. + * + * This implementation contains an optimized path for 3-by-3 matrices + * which is especially useful for plane fitting. + * + * \note Currently, it requires two temporary vectors to hold the intermediate + * Householder coefficients, and to reconstruct the matrix Q from the Householder + * reflectors. + * + * Example (this uses the same matrix as the example in + * Tridiagonalization::Tridiagonalization(const MatrixType&)): + * \include Tridiagonalization_decomposeInPlace.cpp + * Output: \verbinclude Tridiagonalization_decomposeInPlace.out + * + * \sa class Tridiagonalization + */ +template<typename MatrixType, typename DiagonalType, typename SubDiagonalType> +void ei_tridiagonalization_inplace(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ) { + typedef typename MatrixType::Index Index; Index n = mat.rows(); ei_assert(mat.cols()==n && diag.size()==n && subdiag.size()==n-1); - if (n==3 && (!NumTraits<Scalar>::IsComplex) ) - { - _decomposeInPlace3x3(mat, diag, subdiag, extractQ); - } - else + ei_tridiagonalization_inplace_selector<MatrixType>::run(mat, diag, subdiag, extractQ); +} + +/** \internal + * General full tridiagonalization + */ +template<typename MatrixType, int Size> +struct ei_tridiagonalization_inplace_selector +{ + typedef typename Tridiagonalization<MatrixType>::CoeffVectorType CoeffVectorType; + typedef typename Tridiagonalization<MatrixType>::HouseholderSequenceType HouseholderSequenceType; + typedef typename MatrixType::Index Index; + template<typename DiagonalType, typename SubDiagonalType> + static void run(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ) { - Tridiagonalization tridiag(mat); - diag = tridiag.diagonal(); - subdiag = tridiag.subDiagonal(); - if (extractQ) - mat = tridiag.matrixQ(); + CoeffVectorType hCoeffs(mat.cols()-1); + ei_tridiagonalization_inplace(mat,hCoeffs); + diag = mat.diagonal().real(); + subdiag = mat.template diagonal<-1>().real(); + if(extractQ) + mat = HouseholderSequenceType(mat, hCoeffs.conjugate(), false, mat.rows() - 1, 1); } -} +}; /** \internal - * Optimized path for 3x3 matrices. + * Specialization for 3x3 matrices. * Especially useful for plane fitting. */ template<typename MatrixType> -void Tridiagonalization<MatrixType>::_decomposeInPlace3x3(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ) +struct ei_tridiagonalization_inplace_selector<MatrixType,3> { - diag[0] = ei_real(mat(0,0)); - RealScalar v1norm2 = ei_abs2(mat(0,2)); - if (ei_isMuchSmallerThan(v1norm2, RealScalar(1))) - { - diag[1] = ei_real(mat(1,1)); - diag[2] = ei_real(mat(2,2)); - subdiag[0] = ei_real(mat(0,1)); - subdiag[1] = ei_real(mat(1,2)); - if (extractQ) - mat.setIdentity(); - } - else + typedef typename MatrixType::Scalar Scalar; + typedef typename MatrixType::RealScalar RealScalar; + + template<typename DiagonalType, typename SubDiagonalType> + static void run(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ) { - RealScalar beta = ei_sqrt(ei_abs2(mat(0,1))+v1norm2); - RealScalar invBeta = RealScalar(1)/beta; - Scalar m01 = mat(0,1) * invBeta; - Scalar m02 = mat(0,2) * invBeta; - Scalar q = RealScalar(2)*m01*mat(1,2) + m02*(mat(2,2) - mat(1,1)); - diag[1] = ei_real(mat(1,1) + m02*q); - diag[2] = ei_real(mat(2,2) - m02*q); - subdiag[0] = beta; - subdiag[1] = ei_real(mat(1,2) - m01 * q); - if (extractQ) + diag[0] = ei_real(mat(0,0)); + RealScalar v1norm2 = ei_abs2(mat(2,0)); + if (ei_isMuchSmallerThan(v1norm2, RealScalar(1))) + { + diag[1] = ei_real(mat(1,1)); + diag[2] = ei_real(mat(2,2)); + subdiag[0] = ei_real(mat(1,0)); + subdiag[1] = ei_real(mat(2,1)); + if (extractQ) + mat.setIdentity(); + } + else { - mat(0,0) = 1; - mat(0,1) = 0; - mat(0,2) = 0; - mat(1,0) = 0; - mat(1,1) = m01; - mat(1,2) = m02; - mat(2,0) = 0; - mat(2,1) = m02; - mat(2,2) = -m01; + RealScalar beta = ei_sqrt(ei_abs2(mat(1,0)) + v1norm2); + RealScalar invBeta = RealScalar(1)/beta; + Scalar m01 = ei_conj(mat(1,0)) * invBeta; + Scalar m02 = ei_conj(mat(2,0)) * invBeta; + Scalar q = RealScalar(2)*m01*ei_conj(mat(2,1)) + m02*(mat(2,2) - mat(1,1)); + diag[1] = ei_real(mat(1,1) + m02*q); + diag[2] = ei_real(mat(2,2) - m02*q); + subdiag[0] = beta; + subdiag[1] = ei_real(ei_conj(mat(2,1)) - m01 * q); + if (extractQ) + { + mat << 1, 0, 0, + 0, m01, m02, + 0, m02, -m01; + } } } -} +}; -#endif // EIGEN_HIDE_HEAVY_CODE +/** \internal + * Trivial specialization for 1x1 matrices + */ +template<typename MatrixType> +struct ei_tridiagonalization_inplace_selector<MatrixType,1> +{ + typedef typename MatrixType::Scalar Scalar; + template<typename DiagonalType, typename SubDiagonalType> + static void run(MatrixType& mat, DiagonalType& diag, SubDiagonalType&, bool extractQ) + { + diag(0,0) = ei_real(mat(0,0)); + if(extractQ) + mat(0,0) = Scalar(1); + } +}; #endif // EIGEN_TRIDIAGONALIZATION_H diff --git a/Eigen/src/Geometry/Scaling.h b/Eigen/src/Geometry/Scaling.h index 27bbec8cd..0de014f62 100644 --- a/Eigen/src/Geometry/Scaling.h +++ b/Eigen/src/Geometry/Scaling.h @@ -174,7 +174,7 @@ template<int Dim,int Mode> inline Transform<Scalar,Dim,Mode> UniformScaling<Scalar>::operator* (const Transform<Scalar,Dim, Mode>& t) const { - Transform<Scalar,Dim> res = t; + Transform<Scalar,Dim,Mode> res = t; res.prescale(factor()); return res; } diff --git a/Eigen/src/Householder/HouseholderSequence.h b/Eigen/src/Householder/HouseholderSequence.h index 90c5bf8a2..b33fe5eeb 100644 --- a/Eigen/src/Householder/HouseholderSequence.h +++ b/Eigen/src/Householder/HouseholderSequence.h @@ -53,6 +53,7 @@ template<typename VectorsType, typename CoeffsType, int Side> struct ei_traits<HouseholderSequence<VectorsType,CoeffsType,Side> > { typedef typename VectorsType::Scalar Scalar; + typedef typename VectorsType::Index Index; typedef typename VectorsType::StorageKind StorageKind; enum { RowsAtCompileTime = Side==OnTheLeft ? ei_traits<VectorsType>::RowsAtCompileTime @@ -159,18 +160,45 @@ template<typename VectorsType, typename CoeffsType, int Side> class HouseholderS template<typename DestType> void evalTo(DestType& dst) const { Index vecs = m_actualVectors; - dst.setIdentity(rows(), rows()); + // FIXME find a way to pass this temporary if the user want to Matrix<Scalar, DestType::RowsAtCompileTime, 1, - AutoAlign|ColMajor, DestType::MaxRowsAtCompileTime, 1> temp(rows()); - for(Index k = vecs-1; k >= 0; --k) + AutoAlign|ColMajor, DestType::MaxRowsAtCompileTime, 1> temp(rows()); + if( ei_is_same_type<typename ei_cleantype<VectorsType>::type,DestType>::ret + && ei_extract_data(dst) == ei_extract_data(m_vectors)) + { + // in-place + dst.diagonal().setOnes(); + dst.template triangularView<StrictlyUpper>().setZero(); + for(Index k = vecs-1; k >= 0; --k) + { + Index cornerSize = rows() - k - m_shift; + if(m_trans) + dst.bottomRightCorner(cornerSize, cornerSize) + .applyHouseholderOnTheRight(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); + else + dst.bottomRightCorner(cornerSize, cornerSize) + .applyHouseholderOnTheLeft(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); + + // clear the off diagonal vector + dst.col(k).tail(rows()-k-1).setZero(); + } + // clear the remaining columns if needed + for(Index k = 0; k<cols()-vecs ; ++k) + dst.col(k).tail(rows()-k-1).setZero(); + } + else { - Index cornerSize = rows() - k - m_shift; - if(m_trans) - dst.bottomRightCorner(cornerSize, cornerSize) - .applyHouseholderOnTheRight(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); - else - dst.bottomRightCorner(cornerSize, cornerSize) - .applyHouseholderOnTheLeft(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); + dst.setIdentity(rows(), rows()); + for(Index k = vecs-1; k >= 0; --k) + { + Index cornerSize = rows() - k - m_shift; + if(m_trans) + dst.bottomRightCorner(cornerSize, cornerSize) + .applyHouseholderOnTheRight(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); + else + dst.bottomRightCorner(cornerSize, cornerSize) + .applyHouseholderOnTheLeft(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); + } } } diff --git a/Eigen/src/LU/FullPivLU.h b/Eigen/src/LU/FullPivLU.h index 32ac99d16..114cd4c7a 100644 --- a/Eigen/src/LU/FullPivLU.h +++ b/Eigen/src/LU/FullPivLU.h @@ -69,7 +69,7 @@ template<typename _MatrixType> class FullPivLU typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar; typedef typename ei_traits<MatrixType>::StorageKind StorageKind; - typedef typename ei_index<StorageKind>::type Index; + typedef typename MatrixType::Index Index; typedef typename ei_plain_row_type<MatrixType, Index>::type IntRowVectorType; typedef typename ei_plain_col_type<MatrixType, Index>::type IntColVectorType; typedef PermutationMatrix<ColsAtCompileTime, MaxColsAtCompileTime> PermutationQType; diff --git a/Eigen/src/LU/Inverse.h b/Eigen/src/LU/Inverse.h index ed1724dda..5ccc59a32 100644 --- a/Eigen/src/LU/Inverse.h +++ b/Eigen/src/LU/Inverse.h @@ -284,7 +284,6 @@ struct ei_inverse_impl : public ReturnByValue<ei_inverse_impl<MatrixType> > typedef typename MatrixType::Index Index; typedef typename ei_eval<MatrixType>::type MatrixTypeNested; typedef typename ei_cleantype<MatrixTypeNested>::type MatrixTypeNestedCleaned; - const MatrixTypeNested m_matrix; ei_inverse_impl(const MatrixType& matrix) @@ -296,6 +295,10 @@ struct ei_inverse_impl : public ReturnByValue<ei_inverse_impl<MatrixType> > template<typename Dest> inline void evalTo(Dest& dst) const { + const int Size = EIGEN_ENUM_MIN(MatrixType::ColsAtCompileTime,Dest::ColsAtCompileTime); + ei_assert(( (Size<=1) || (Size>4) || (ei_extract_data(m_matrix)!=ei_extract_data(dst))) + && "Aliasing problem detected in inverse(), you need to do inverse().eval() here."); + ei_compute_inverse<MatrixTypeNestedCleaned, Dest>::run(m_matrix, dst); } }; @@ -354,7 +357,14 @@ inline void MatrixBase<Derived>::computeInverseAndDetWithCheck( { // i'd love to put some static assertions there, but SFINAE means that they have no effect... ei_assert(rows() == cols()); - ei_compute_inverse_and_det_with_check<PlainObject, ResultType>::run + // for 2x2, it's worth giving a chance to avoid evaluating. + // for larger sizes, evaluating has negligible cost and limits code size. + typedef typename ei_meta_if< + RowsAtCompileTime == 2, + typename ei_cleantype<typename ei_nested<Derived, 2>::type>::type, + PlainObject + >::ret MatrixType; + ei_compute_inverse_and_det_with_check<MatrixType, ResultType>::run (derived(), absDeterminantThreshold, inverse, determinant, invertible); } diff --git a/Eigen/src/LU/PartialPivLU.h b/Eigen/src/LU/PartialPivLU.h index 39c348e5e..7e7516a5c 100644 --- a/Eigen/src/LU/PartialPivLU.h +++ b/Eigen/src/LU/PartialPivLU.h @@ -72,9 +72,9 @@ template<typename _MatrixType> class PartialPivLU typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar; typedef typename ei_traits<MatrixType>::StorageKind StorageKind; - typedef typename ei_index<StorageKind>::type Index; - typedef typename ei_plain_col_type<MatrixType, Index>::type PermutationVectorType; + typedef typename MatrixType::Index Index; typedef PermutationMatrix<RowsAtCompileTime, MaxRowsAtCompileTime> PermutationType; + typedef Transpositions<RowsAtCompileTime, MaxRowsAtCompileTime> TranspositionType; /** @@ -186,7 +186,7 @@ template<typename _MatrixType> class PartialPivLU protected: MatrixType m_lu; PermutationType m_p; - PermutationVectorType m_rowsTranspositions; + TranspositionType m_rowsTranspositions; Index m_det_p; bool m_isInitialized; }; @@ -339,9 +339,9 @@ struct ei_partial_lu_impl Index tsize = size - k - bs; // trailing size // partition the matrix: - // A00 | A01 | A02 - // lu = A10 | A11 | A12 - // A20 | A21 | A22 + // A00 | A01 | A02 + // lu = A_0 | A_1 | A_2 = A10 | A11 | A12 + // A20 | A21 | A22 BlockType A_0(lu,0,0,rows,k); BlockType A_2(lu,0,k+bs,rows,tsize); BlockType A11(lu,k,k,bs,bs); @@ -350,8 +350,8 @@ struct ei_partial_lu_impl BlockType A22(lu,k+bs,k+bs,trows,tsize); Index nb_transpositions_in_panel; - // recursively calls the blocked LU algorithm with a very small - // blocking size: + // recursively call the blocked LU algorithm on [A11^T A21^T]^T + // with a very small blocking size: if(!blocked_lu(trows+bs, bs, &lu.coeffRef(k,k), luStride, row_transpositions+k, nb_transpositions_in_panel, 16)) { @@ -364,7 +364,7 @@ struct ei_partial_lu_impl } nb_transpositions += nb_transpositions_in_panel; - // update permutations and apply them to A10 + // update permutations and apply them to A_0 for(Index i=k; i<k+bs; ++i) { Index piv = (row_transpositions[i] += k); @@ -389,8 +389,8 @@ struct ei_partial_lu_impl /** \internal performs the LU decomposition with partial pivoting in-place. */ -template<typename MatrixType, typename IntVector> -void ei_partial_lu_inplace(MatrixType& lu, IntVector& row_transpositions, typename MatrixType::Index& nb_transpositions) +template<typename MatrixType, typename TranspositionType> +void ei_partial_lu_inplace(MatrixType& lu, TranspositionType& row_transpositions, typename MatrixType::Index& nb_transpositions) { ei_assert(lu.cols() == row_transpositions.size()); ei_assert((&row_transpositions.coeffRef(1)-&row_transpositions.coeffRef(0)) == 1); @@ -414,9 +414,7 @@ PartialPivLU<MatrixType>& PartialPivLU<MatrixType>::compute(const MatrixType& ma ei_partial_lu_inplace(m_lu, m_rowsTranspositions, nb_transpositions); m_det_p = (nb_transpositions%2) ? -1 : 1; - m_p.setIdentity(size); - for(Index k = size-1; k >= 0; --k) - m_p.applyTranspositionOnTheRight(k, m_rowsTranspositions.coeff(k)); + m_p = m_rowsTranspositions; m_isInitialized = true; return *this; diff --git a/Eigen/src/QR/ColPivHouseholderQR.h b/Eigen/src/QR/ColPivHouseholderQR.h index b4bcfd529..6914d6873 100644 --- a/Eigen/src/QR/ColPivHouseholderQR.h +++ b/Eigen/src/QR/ColPivHouseholderQR.h @@ -286,6 +286,7 @@ template<typename _MatrixType> class ColPivHouseholderQR { m_usePrescribedThreshold = true; m_prescribedThreshold = threshold; + return *this; } /** Allows to come back to the default behavior, letting Eigen use its default formula for @@ -299,6 +300,7 @@ template<typename _MatrixType> class ColPivHouseholderQR ColPivHouseholderQR& setThreshold(Default_t) { m_usePrescribedThreshold = false; + return *this; } /** Returns the threshold that will be used by certain methods such as rank(). @@ -345,8 +347,6 @@ template<typename _MatrixType> class ColPivHouseholderQR Index m_det_pq; }; -#ifndef EIGEN_HIDE_HEAVY_CODE - template<typename MatrixType> typename MatrixType::RealScalar ColPivHouseholderQR<MatrixType>::absDeterminant() const { @@ -511,8 +511,6 @@ typename ColPivHouseholderQR<MatrixType>::HouseholderSequenceType ColPivHousehol return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate(), false, m_nonzero_pivots, 0); } -#endif // EIGEN_HIDE_HEAVY_CODE - /** \return the column-pivoting Householder QR decomposition of \c *this. * * \sa class ColPivHouseholderQR diff --git a/Eigen/src/QR/FullPivHouseholderQR.h b/Eigen/src/QR/FullPivHouseholderQR.h index 3b4d02d67..cfb0b30a9 100644 --- a/Eigen/src/QR/FullPivHouseholderQR.h +++ b/Eigen/src/QR/FullPivHouseholderQR.h @@ -271,8 +271,6 @@ template<typename _MatrixType> class FullPivHouseholderQR Index m_det_pq; }; -#ifndef EIGEN_HIDE_HEAVY_CODE - template<typename MatrixType> typename MatrixType::RealScalar FullPivHouseholderQR<MatrixType>::absDeterminant() const { @@ -437,8 +435,6 @@ typename FullPivHouseholderQR<MatrixType>::MatrixQType FullPivHouseholderQR<Matr return res; } -#endif // EIGEN_HIDE_HEAVY_CODE - /** \return the full-pivoting Householder QR decomposition of \c *this. * * \sa class FullPivHouseholderQR diff --git a/Eigen/src/QR/HouseholderQR.h b/Eigen/src/QR/HouseholderQR.h index a8caaccea..0eea47676 100644 --- a/Eigen/src/QR/HouseholderQR.h +++ b/Eigen/src/QR/HouseholderQR.h @@ -177,8 +177,6 @@ template<typename _MatrixType> class HouseholderQR bool m_isInitialized; }; -#ifndef EIGEN_HIDE_HEAVY_CODE - template<typename MatrixType> typename MatrixType::RealScalar HouseholderQR<MatrixType>::absDeterminant() const { @@ -254,8 +252,6 @@ struct ei_solve_retval<HouseholderQR<_MatrixType>, Rhs> } }; -#endif // EIGEN_HIDE_HEAVY_CODE - /** \return the Householder QR decomposition of \c *this. * * \sa class HouseholderQR diff --git a/Eigen/src/Sparse/AmbiVector.h b/Eigen/src/Sparse/AmbiVector.h index 7b18f8cc2..673cb32a5 100644 --- a/Eigen/src/Sparse/AmbiVector.h +++ b/Eigen/src/Sparse/AmbiVector.h @@ -30,12 +30,14 @@ * * See BasicSparseLLT and SparseProduct for usage examples. */ -template<typename _Scalar> class AmbiVector +template<typename _Scalar, typename _Index> +class AmbiVector { public: typedef _Scalar Scalar; + typedef _Index Index; typedef typename NumTraits<Scalar>::Real RealScalar; - typedef SparseIndex Index; + AmbiVector(Index size) : m_buffer(0), m_zero(0), m_size(0), m_allocatedSize(0), m_allocatedElements(0), m_mode(-1) { @@ -130,8 +132,8 @@ template<typename _Scalar> class AmbiVector }; /** \returns the number of non zeros in the current sub vector */ -template<typename Scalar> -SparseIndex AmbiVector<Scalar>::nonZeros() const +template<typename _Scalar,typename _Index> +_Index AmbiVector<_Scalar,_Index>::nonZeros() const { if (m_mode==IsSparse) return m_llSize; @@ -139,8 +141,8 @@ SparseIndex AmbiVector<Scalar>::nonZeros() const return m_end - m_start; } -template<typename Scalar> -void AmbiVector<Scalar>::init(double estimatedDensity) +template<typename _Scalar,typename _Index> +void AmbiVector<_Scalar,_Index>::init(double estimatedDensity) { if (estimatedDensity>0.1) init(IsDense); @@ -148,8 +150,8 @@ void AmbiVector<Scalar>::init(double estimatedDensity) init(IsSparse); } -template<typename Scalar> -void AmbiVector<Scalar>::init(int mode) +template<typename _Scalar,typename _Index> +void AmbiVector<_Scalar,_Index>::init(int mode) { m_mode = mode; if (m_mode==IsSparse) @@ -164,15 +166,15 @@ void AmbiVector<Scalar>::init(int mode) * * Don't worry, this function is extremely cheap. */ -template<typename Scalar> -void AmbiVector<Scalar>::restart() +template<typename _Scalar,typename _Index> +void AmbiVector<_Scalar,_Index>::restart() { m_llCurrent = m_llStart; } /** Set all coefficients of current subvector to zero */ -template<typename Scalar> -void AmbiVector<Scalar>::setZero() +template<typename _Scalar,typename _Index> +void AmbiVector<_Scalar,_Index>::setZero() { if (m_mode==IsDense) { @@ -187,8 +189,8 @@ void AmbiVector<Scalar>::setZero() } } -template<typename Scalar> -Scalar& AmbiVector<Scalar>::coeffRef(Index i) +template<typename _Scalar,typename _Index> +_Scalar& AmbiVector<_Scalar,_Index>::coeffRef(_Index i) { if (m_mode==IsDense) return m_buffer[i]; @@ -256,8 +258,8 @@ Scalar& AmbiVector<Scalar>::coeffRef(Index i) } } -template<typename Scalar> -Scalar& AmbiVector<Scalar>::coeff(Index i) +template<typename _Scalar,typename _Index> +_Scalar& AmbiVector<_Scalar,_Index>::coeff(_Index i) { if (m_mode==IsDense) return m_buffer[i]; @@ -284,8 +286,8 @@ Scalar& AmbiVector<Scalar>::coeff(Index i) } /** Iterator over the nonzero coefficients */ -template<typename _Scalar> -class AmbiVector<_Scalar>::Iterator +template<typename _Scalar,typename _Index> +class AmbiVector<_Scalar,_Index>::Iterator { public: typedef _Scalar Scalar; diff --git a/Eigen/src/Sparse/CholmodSupport.h b/Eigen/src/Sparse/CholmodSupport.h index 82a09f35c..a8d7a8fec 100644 --- a/Eigen/src/Sparse/CholmodSupport.h +++ b/Eigen/src/Sparse/CholmodSupport.h @@ -109,8 +109,8 @@ cholmod_dense ei_cholmod_map_eigen_to_dense(MatrixBase<Derived>& mat) return res; } -template<typename Scalar, int Flags> -MappedSparseMatrix<Scalar,Flags>::MappedSparseMatrix(cholmod_sparse& cm) +template<typename Scalar, int Flags, typename _Index> +MappedSparseMatrix<Scalar,Flags,_Index>::MappedSparseMatrix(cholmod_sparse& cm) { m_innerSize = cm.nrow; m_outerSize = cm.ncol; @@ -128,6 +128,7 @@ class SparseLLT<MatrixType,Cholmod> : public SparseLLT<MatrixType> typedef typename Base::Scalar Scalar; typedef typename Base::RealScalar RealScalar; typedef typename Base::CholMatrixType CholMatrixType; + typedef typename MatrixType::Index Index; using Base::MatrixLIsDirty; using Base::SupernodalFactorIsDirty; using Base::m_flags; diff --git a/Eigen/src/Sparse/CompressedStorage.h b/Eigen/src/Sparse/CompressedStorage.h index 37d337639..73488f225 100644 --- a/Eigen/src/Sparse/CompressedStorage.h +++ b/Eigen/src/Sparse/CompressedStorage.h @@ -28,12 +28,20 @@ /** Stores a sparse set of values as a list of values and a list of indices. * */ -template<typename Scalar> +template<typename _Scalar,typename _Index> class CompressedStorage { + public: + + typedef _Scalar Scalar; + typedef _Index Index; + + protected: + typedef typename NumTraits<Scalar>::Real RealScalar; - typedef SparseIndex Index; + public: + CompressedStorage() : m_values(0), m_indices(0), m_size(0), m_allocatedSize(0) {} @@ -118,13 +126,13 @@ class CompressedStorage res.m_allocatedSize = res.m_size = size; return res; } - + /** \returns the largest \c k such that for all \c j in [0,k) index[\c j]\<\a key */ inline Index searchLowerIndex(Index key) const { return searchLowerIndex(0, m_size, key); } - + /** \returns the largest \c k in [start,end) such that for all \c j in [start,k) index[\c j]\<\a key */ inline Index searchLowerIndex(size_t start, size_t end, Index key) const { @@ -138,7 +146,7 @@ class CompressedStorage } return static_cast<Index>(start); } - + /** \returns the stored value at index \a key * If the value does not exist, then the value \a defaultValue is returned without any insertion. */ inline Scalar at(Index key, Scalar defaultValue = Scalar(0)) const @@ -152,7 +160,7 @@ class CompressedStorage const size_t id = searchLowerIndex(0,m_size-1,key); return ((id<m_size) && (m_indices[id]==key)) ? m_values[id] : defaultValue; } - + /** Like at(), but the search is performed in the range [start,end) */ inline Scalar atInRange(size_t start, size_t end, Index key, Scalar defaultValue = Scalar(0)) const { @@ -165,7 +173,7 @@ class CompressedStorage const size_t id = searchLowerIndex(start,end-1,key); return ((id<end) && (m_indices[id]==key)) ? m_values[id] : defaultValue; } - + /** \returns a reference to the value at index \a key * If the value does not exist, then the value \a defaultValue is inserted * such that the keys are sorted. */ @@ -185,7 +193,7 @@ class CompressedStorage } return m_values[id]; } - + void prune(Scalar reference, RealScalar epsilon = NumTraits<RealScalar>::dummy_precision()) { size_t k = 0; diff --git a/Eigen/src/Sparse/DynamicSparseMatrix.h b/Eigen/src/Sparse/DynamicSparseMatrix.h index fea707f15..d0ce2b248 100644 --- a/Eigen/src/Sparse/DynamicSparseMatrix.h +++ b/Eigen/src/Sparse/DynamicSparseMatrix.h @@ -42,10 +42,11 @@ * * \see SparseMatrix */ -template<typename _Scalar, int _Flags> -struct ei_traits<DynamicSparseMatrix<_Scalar, _Flags> > +template<typename _Scalar, int _Flags, typename _Index> +struct ei_traits<DynamicSparseMatrix<_Scalar, _Flags, _Index> > { typedef _Scalar Scalar; + typedef _Index Index; typedef Sparse StorageKind; typedef MatrixXpr XprKind; enum { @@ -59,12 +60,12 @@ struct ei_traits<DynamicSparseMatrix<_Scalar, _Flags> > }; }; -template<typename _Scalar, int _Flags> +template<typename _Scalar, int _Flags, typename _Index> class DynamicSparseMatrix - : public SparseMatrixBase<DynamicSparseMatrix<_Scalar, _Flags> > + : public SparseMatrixBase<DynamicSparseMatrix<_Scalar, _Flags, _Index> > { public: - EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(DynamicSparseMatrix) + EIGEN_SPARSE_PUBLIC_INTERFACE(DynamicSparseMatrix) // FIXME: why are these operator already alvailable ??? // EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(DynamicSparseMatrix, +=) // EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(DynamicSparseMatrix, -=) @@ -76,7 +77,7 @@ class DynamicSparseMatrix typedef DynamicSparseMatrix<Scalar,(Flags&~RowMajorBit)|(IsRowMajor?RowMajorBit:0)> TransposedSparseMatrix; Index m_innerSize; - std::vector<CompressedStorage<Scalar> > m_data; + std::vector<CompressedStorage<Scalar,Index> > m_data; public: @@ -86,8 +87,8 @@ class DynamicSparseMatrix inline Index outerSize() const { return static_cast<Index>(m_data.size()); } inline Index innerNonZeros(Index j) const { return m_data[j].size(); } - std::vector<CompressedStorage<Scalar> >& _data() { return m_data; } - const std::vector<CompressedStorage<Scalar> >& _data() const { return m_data; } + std::vector<CompressedStorage<Scalar,Index> >& _data() { return m_data; } + const std::vector<CompressedStorage<Scalar,Index> >& _data() const { return m_data; } /** \returns the coefficient value at given position \a row, \a col * This operation involes a log(rho*outer_size) binary search. @@ -127,13 +128,7 @@ class DynamicSparseMatrix return res; } - /** \deprecated - * Set the matrix to zero and reserve the memory for \a reserveSize nonzero coefficients. */ - EIGEN_DEPRECATED void startFill(Index reserveSize = 1000) - { - setZero(); - reserve(reserveSize); - } + void reserve(Index reserveSize = 1000) { @@ -147,9 +142,21 @@ class DynamicSparseMatrix } } + /** Does nothing: provided for compatibility with SparseMatrix */ inline void startVec(Index /*outer*/) {} - inline Scalar& insertBack(Index outer, Index inner) + /** \returns a reference to the non zero coefficient at position \a row, \a col assuming that: + * - the nonzero does not already exist + * - the new coefficient is the last one of the given inner vector. + * + * \sa insert, insertBackByOuterInner */ + inline Scalar& insertBack(Index row, Index col) + { + return insertBackByOuterInner(IsRowMajor?row:col, IsRowMajor?col:row); + } + + /** \sa insertBack */ + inline Scalar& insertBackByOuterInner(Index outer, Index inner) { ei_assert(outer<Index(m_data.size()) && inner<m_innerSize && "out of range"); ei_assert(((m_data[outer].size()==0) || (m_data[outer].index(m_data[outer].size()-1)<inner)) @@ -158,32 +165,6 @@ class DynamicSparseMatrix return m_data[outer].value(m_data[outer].size()-1); } - /** \deprecated use insert() - * inserts a nonzero coefficient at given coordinates \a row, \a col and returns its reference assuming that: - * 1 - the coefficient does not exist yet - * 2 - this the coefficient with greater inner coordinate for the given outer coordinate. - * In other words, assuming \c *this is column-major, then there must not exists any nonzero coefficient of coordinates - * \c i \c x \a col such that \c i >= \a row. Otherwise the matrix is invalid. - * - * \see fillrand(), coeffRef() - */ - EIGEN_DEPRECATED Scalar& fill(Index row, Index col) - { - const Index outer = IsRowMajor ? row : col; - const Index inner = IsRowMajor ? col : row; - return insertBack(outer,inner); - } - - /** \deprecated use insert() - * Like fill() but with random inner coordinates. - * Compared to the generic coeffRef(), the unique limitation is that we assume - * the coefficient does not exist yet. - */ - EIGEN_DEPRECATED Scalar& fillrand(Index row, Index col) - { - return insert(row,col); - } - inline Scalar& insert(Index row, Index col) { const Index outer = IsRowMajor ? row : col; @@ -204,12 +185,10 @@ class DynamicSparseMatrix return m_data[outer].value(id+1); } - /** \deprecated use finalize() - * Does nothing. Provided for compatibility with SparseMatrix. */ - EIGEN_DEPRECATED void endFill() {} - + /** Does nothing: provided for compatibility with SparseMatrix */ inline void finalize() {} + /** Suppress all nonzeros which are smaller than \a reference under the tolerence \a epsilon */ void prune(Scalar reference, RealScalar epsilon = NumTraits<RealScalar>::dummy_precision()) { for (Index j=0; j<outerSize(); ++j) @@ -301,10 +280,50 @@ class DynamicSparseMatrix /** Destructor */ inline ~DynamicSparseMatrix() {} + + public: + + /** \deprecated + * Set the matrix to zero and reserve the memory for \a reserveSize nonzero coefficients. */ + EIGEN_DEPRECATED void startFill(Index reserveSize = 1000) + { + setZero(); + reserve(reserveSize); + } + + /** \deprecated use insert() + * inserts a nonzero coefficient at given coordinates \a row, \a col and returns its reference assuming that: + * 1 - the coefficient does not exist yet + * 2 - this the coefficient with greater inner coordinate for the given outer coordinate. + * In other words, assuming \c *this is column-major, then there must not exists any nonzero coefficient of coordinates + * \c i \c x \a col such that \c i >= \a row. Otherwise the matrix is invalid. + * + * \see fillrand(), coeffRef() + */ + EIGEN_DEPRECATED Scalar& fill(Index row, Index col) + { + const Index outer = IsRowMajor ? row : col; + const Index inner = IsRowMajor ? col : row; + return insertBack(outer,inner); + } + + /** \deprecated use insert() + * Like fill() but with random inner coordinates. + * Compared to the generic coeffRef(), the unique limitation is that we assume + * the coefficient does not exist yet. + */ + EIGEN_DEPRECATED Scalar& fillrand(Index row, Index col) + { + return insert(row,col); + } + + /** \deprecated use finalize() + * Does nothing. Provided for compatibility with SparseMatrix. */ + EIGEN_DEPRECATED void endFill() {} }; -template<typename Scalar, int _Flags> -class DynamicSparseMatrix<Scalar,_Flags>::InnerIterator : public SparseVector<Scalar,_Flags>::InnerIterator +template<typename Scalar, int _Flags, typename _Index> +class DynamicSparseMatrix<Scalar,_Flags,_Index>::InnerIterator : public SparseVector<Scalar,_Flags>::InnerIterator { typedef typename SparseVector<Scalar,_Flags>::InnerIterator Base; public: diff --git a/Eigen/src/Sparse/MappedSparseMatrix.h b/Eigen/src/Sparse/MappedSparseMatrix.h index 07233ac67..99aeeb106 100644 --- a/Eigen/src/Sparse/MappedSparseMatrix.h +++ b/Eigen/src/Sparse/MappedSparseMatrix.h @@ -34,25 +34,25 @@ * See http://www.netlib.org/linalg/html_templates/node91.html for details on the storage scheme. * */ -template<typename _Scalar, int _Flags> -struct ei_traits<MappedSparseMatrix<_Scalar, _Flags> > : ei_traits<SparseMatrix<_Scalar, _Flags> > +template<typename _Scalar, int _Flags, typename _Index> +struct ei_traits<MappedSparseMatrix<_Scalar, _Flags, _Index> > : ei_traits<SparseMatrix<_Scalar, _Flags, _Index> > {}; -template<typename _Scalar, int _Flags> +template<typename _Scalar, int _Flags, typename _Index> class MappedSparseMatrix - : public SparseMatrixBase<MappedSparseMatrix<_Scalar, _Flags> > + : public SparseMatrixBase<MappedSparseMatrix<_Scalar, _Flags, _Index> > { public: - EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(MappedSparseMatrix) + EIGEN_SPARSE_PUBLIC_INTERFACE(MappedSparseMatrix) protected: enum { IsRowMajor = Base::IsRowMajor }; - Index m_outerSize; - Index m_innerSize; - Index m_nnz; - Index* m_outerIndex; - Index* m_innerIndices; + Index m_outerSize; + Index m_innerSize; + Index m_nnz; + Index* m_outerIndex; + Index* m_innerIndices; Scalar* m_values; public: @@ -135,8 +135,8 @@ class MappedSparseMatrix inline ~MappedSparseMatrix() {} }; -template<typename Scalar, int _Flags> -class MappedSparseMatrix<Scalar,_Flags>::InnerIterator +template<typename Scalar, int _Flags, typename _Index> +class MappedSparseMatrix<Scalar,_Flags,_Index>::InnerIterator { public: InnerIterator(const MappedSparseMatrix& mat, Index outer) diff --git a/Eigen/src/Sparse/RandomSetter.h b/Eigen/src/Sparse/RandomSetter.h index abe98815f..18777e23d 100644 --- a/Eigen/src/Sparse/RandomSetter.h +++ b/Eigen/src/Sparse/RandomSetter.h @@ -243,7 +243,7 @@ class RandomSetter mp_target->startVec(j); prevOuter = outer; } - mp_target->insertBack(outer, inner) = it->second.value; + mp_target->insertBackByOuterInner(outer, inner) = it->second.value; } } mp_target->finalize(); diff --git a/Eigen/src/Sparse/SparseBlock.h b/Eigen/src/Sparse/SparseBlock.h index bf8b5adc7..8e530182d 100644 --- a/Eigen/src/Sparse/SparseBlock.h +++ b/Eigen/src/Sparse/SparseBlock.h @@ -29,6 +29,7 @@ template<typename MatrixType, int Size> struct ei_traits<SparseInnerVectorSet<MatrixType, Size> > { typedef typename ei_traits<MatrixType>::Scalar Scalar; + typedef typename ei_traits<MatrixType>::Index Index; typedef typename ei_traits<MatrixType>::StorageKind StorageKind; typedef MatrixXpr XprKind; enum { @@ -50,7 +51,7 @@ class SparseInnerVectorSet : ei_no_assignment_operator, enum { IsRowMajor = ei_traits<SparseInnerVectorSet>::IsRowMajor }; - EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(SparseInnerVectorSet) + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseInnerVectorSet) class InnerIterator: public MatrixType::InnerIterator { public: @@ -111,7 +112,7 @@ class SparseInnerVectorSet<DynamicSparseMatrix<_Scalar, _Options>, Size> enum { IsRowMajor = ei_traits<SparseInnerVectorSet>::IsRowMajor }; - EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(SparseInnerVectorSet) + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseInnerVectorSet) class InnerIterator: public MatrixType::InnerIterator { public: @@ -209,7 +210,7 @@ class SparseInnerVectorSet<SparseMatrix<_Scalar, _Options>, Size> enum { IsRowMajor = ei_traits<SparseInnerVectorSet>::IsRowMajor }; - EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(SparseInnerVectorSet) + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseInnerVectorSet) class InnerIterator: public MatrixType::InnerIterator { public: diff --git a/Eigen/src/Sparse/SparseDiagonalProduct.h b/Eigen/src/Sparse/SparseDiagonalProduct.h index 70b35bc23..f5da2c269 100644 --- a/Eigen/src/Sparse/SparseDiagonalProduct.h +++ b/Eigen/src/Sparse/SparseDiagonalProduct.h @@ -43,6 +43,8 @@ struct ei_traits<SparseDiagonalProduct<Lhs, Rhs> > typedef typename ei_cleantype<Lhs>::type _Lhs; typedef typename ei_cleantype<Rhs>::type _Rhs; typedef typename _Lhs::Scalar Scalar; + typedef typename ei_promote_index_type<typename ei_traits<Lhs>::Index, + typename ei_traits<Rhs>::Index>::type Index; typedef Sparse StorageKind; typedef MatrixXpr XprKind; enum { @@ -82,7 +84,7 @@ class SparseDiagonalProduct public: - EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(SparseDiagonalProduct) + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseDiagonalProduct) typedef ei_sparse_diagonal_product_inner_iterator_selector <_LhsNested,_RhsNested,SparseDiagonalProduct,LhsMode,RhsMode> InnerIterator; diff --git a/Eigen/src/Sparse/SparseLDLT.h b/Eigen/src/Sparse/SparseLDLT.h index b6a51c6a6..a6785d0af 100644 --- a/Eigen/src/Sparse/SparseLDLT.h +++ b/Eigen/src/Sparse/SparseLDLT.h @@ -71,6 +71,8 @@ LDL License: * * \param MatrixType the type of the matrix of which we are computing the LDLT Cholesky decomposition * + * \warning the upper triangular part has to be specified. The rest of the matrix is not used. The input matrix must be column major. + * * \sa class LDLT, class LDLT */ template<typename MatrixType, int Backend = DefaultBackend> @@ -213,7 +215,7 @@ void SparseLDLT<MatrixType,Backend>::_symbolic(const MatrixType& a) m_parent[k] = -1; /* parent of k is not yet known */ tags[k] = k; /* mark node k as visited */ m_nonZerosPerCol[k] = 0; /* count of nonzeros in column k of L */ - Index kk = P ? P[k] : k; /* kth original, or permuted, column */ + Index kk = P ? P[k] : k; /* kth original, or permuted, column */ Index p2 = Ap[kk+1]; for (Index p = Ap[kk]; p < p2; ++p) { @@ -269,10 +271,10 @@ bool SparseLDLT<MatrixType,Backend>::_numeric(const MatrixType& a) for (Index k = 0; k < size; ++k) { /* compute nonzero pattern of kth row of L, in topological order */ - y[k] = 0.0; /* Y(0:k) is now all zero */ + y[k] = 0.0; /* Y(0:k) is now all zero */ Index top = size; /* stack for pattern is empty */ - tags[k] = k; /* mark node k as visited */ - m_nonZerosPerCol[k] = 0; /* count of nonzeros in column k of L */ + tags[k] = k; /* mark node k as visited */ + m_nonZerosPerCol[k] = 0; /* count of nonzeros in column k of L */ Index kk = (P) ? (P[k]) : (k); /* kth original, or permuted, column */ Index p2 = Ap[kk+1]; for (Index p = Ap[kk]; p < p2; ++p) @@ -280,7 +282,7 @@ bool SparseLDLT<MatrixType,Backend>::_numeric(const MatrixType& a) Index i = Pinv ? Pinv[Ai[p]] : Ai[p]; /* get A(i,k) */ if (i <= k) { - y[i] += Ax[p]; /* scatter A(i,k) into Y (sum duplicates) */ + y[i] += ei_conj(Ax[p]); /* scatter A(i,k) into Y (sum duplicates) */ Index len; for (len = 0; tags[i] != k; i = m_parent[i]) { @@ -291,22 +293,23 @@ bool SparseLDLT<MatrixType,Backend>::_numeric(const MatrixType& a) pattern[--top] = pattern[--len]; } } + /* compute numerical values kth row of L (a sparse triangular solve) */ m_diag[k] = y[k]; /* get D(k,k) and clear Y(k) */ y[k] = 0.0; for (; top < size; ++top) { - Index i = pattern[top]; /* pattern[top:n-1] is pattern of L(:,k) */ - Scalar yi = y[i]; /* get and clear Y(i) */ + Index i = pattern[top]; /* pattern[top:n-1] is pattern of L(:,k) */ + Scalar yi = (y[i]); /* get and clear Y(i) */ y[i] = 0.0; Index p2 = Lp[i] + m_nonZerosPerCol[i]; Index p; for (p = Lp[i]; p < p2; ++p) - y[Li[p]] -= Lx[p] * yi; + y[Li[p]] -= ei_conj(Lx[p]) * (yi); Scalar l_ki = yi / m_diag[i]; /* the nonzero entry L(k,i) */ - m_diag[k] -= l_ki * yi; + m_diag[k] -= l_ki * ei_conj(yi); Li[p] = k; /* store L(k,i) in column form of L */ - Lx[p] = l_ki; + Lx[p] = (l_ki); ++m_nonZerosPerCol[i]; /* increment count of nonzeros in col i */ } if (m_diag[k] == 0.0) @@ -323,7 +326,7 @@ bool SparseLDLT<MatrixType,Backend>::_numeric(const MatrixType& a) return ok; /* success, diagonal of D is all nonzero */ } -/** Computes b = L^-T L^-1 b */ +/** Computes b = L^-T D^-1 L^-1 b */ template<typename MatrixType, int Backend> template<typename Derived> bool SparseLDLT<MatrixType, Backend>::solveInPlace(MatrixBase<Derived> &b) const @@ -336,10 +339,8 @@ bool SparseLDLT<MatrixType, Backend>::solveInPlace(MatrixBase<Derived> &b) const if (m_matrix.nonZeros()>0) // otherwise L==I m_matrix.template triangularView<UnitLower>().solveInPlace(b); b = b.cwiseQuotient(m_diag); - // FIXME should be .adjoint() but it fails to compile... - if (m_matrix.nonZeros()>0) // otherwise L==I - m_matrix.transpose().template triangularView<UnitUpper>().solveInPlace(b); + m_matrix.adjoint().template triangularView<UnitUpper>().solveInPlace(b); return true; } diff --git a/Eigen/src/Sparse/SparseLLT.h b/Eigen/src/Sparse/SparseLLT.h index 37c6c3f9a..47d58f8e6 100644 --- a/Eigen/src/Sparse/SparseLLT.h +++ b/Eigen/src/Sparse/SparseLLT.h @@ -132,7 +132,7 @@ void SparseLLT<MatrixType,Backend>::compute(const MatrixType& a) m_matrix.resize(size, size); // allocate a temporary vector for accumulations - AmbiVector<Scalar> tempVector(size); + AmbiVector<Scalar,Index> tempVector(size); RealScalar density = a.nonZeros()/RealScalar(size*size); // TODO estimate the number of non zeros @@ -177,7 +177,7 @@ void SparseLLT<MatrixType,Backend>::compute(const MatrixType& a) RealScalar rx = ei_sqrt(ei_real(x)); m_matrix.insert(j,j) = rx; // FIXME use insertBack Scalar y = Scalar(1)/rx; - for (typename AmbiVector<Scalar>::Iterator it(tempVector, m_precision*rx); it; ++it) + for (typename AmbiVector<Scalar,Index>::Iterator it(tempVector, m_precision*rx); it; ++it) { // FIXME use insertBack m_matrix.insert(it.index(), j) = it.value() * y; @@ -195,14 +195,7 @@ bool SparseLLT<MatrixType, Backend>::solveInPlace(MatrixBase<Derived> &b) const ei_assert(size==b.rows()); m_matrix.template triangularView<Lower>().solveInPlace(b); - // FIXME should be simply .adjoint() but it fails to compile... - if (NumTraits<Scalar>::IsComplex) - { - CholMatrixType aux = m_matrix.conjugate(); - aux.transpose().template triangularView<Upper>().solveInPlace(b); - } - else - m_matrix.transpose().template triangularView<Upper>().solveInPlace(b); + m_matrix.adjoint().template triangularView<Upper>().solveInPlace(b); return true; } diff --git a/Eigen/src/Sparse/SparseMatrix.h b/Eigen/src/Sparse/SparseMatrix.h index fd41d7302..e8e947eea 100644 --- a/Eigen/src/Sparse/SparseMatrix.h +++ b/Eigen/src/Sparse/SparseMatrix.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr> +// Copyright (C) 2008-2010 Gael Guennebaud <g.gael@free.fr> // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -37,14 +37,16 @@ * \param _Scalar the scalar type, i.e. the type of the coefficients * \param _Options Union of bit flags controlling the storage scheme. Currently the only possibility * is RowMajor. The default is 0 which means column-major. + * \param _Index the type of the indices. Default is \c int. * * See http://www.netlib.org/linalg/html_templates/node91.html for details on the storage scheme. * */ -template<typename _Scalar, int _Options> -struct ei_traits<SparseMatrix<_Scalar, _Options> > +template<typename _Scalar, int _Options, typename _Index> +struct ei_traits<SparseMatrix<_Scalar, _Options, _Index> > { typedef _Scalar Scalar; + typedef _Index Index; typedef Sparse StorageKind; typedef MatrixXpr XprKind; enum { @@ -58,12 +60,12 @@ struct ei_traits<SparseMatrix<_Scalar, _Options> > }; }; -template<typename _Scalar, int _Options> +template<typename _Scalar, int _Options, typename _Index> class SparseMatrix - : public SparseMatrixBase<SparseMatrix<_Scalar, _Options> > + : public SparseMatrixBase<SparseMatrix<_Scalar, _Options, _Index> > { public: - EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(SparseMatrix) + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseMatrix) EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseMatrix, +=) EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseMatrix, -=) // FIXME: why are these operator already alvailable ??? @@ -80,7 +82,7 @@ class SparseMatrix Index m_outerSize; Index m_innerSize; Index* m_outerIndex; - CompressedStorage<Scalar> m_data; + CompressedStorage<Scalar,Index> m_data; public: @@ -135,67 +137,41 @@ class SparseMatrix /** \returns the number of non zero coefficients */ inline Index nonZeros() const { return static_cast<Index>(m_data.size()); } - /** \deprecated use setZero() and reserve() - * Initializes the filling process of \c *this. - * \param reserveSize approximate number of nonzeros - * Note that the matrix \c *this is zero-ed. - */ - EIGEN_DEPRECATED void startFill(Index reserveSize = 1000) - { - setZero(); - m_data.reserve(reserveSize); - } - /** Preallocates \a reserveSize non zeros */ inline void reserve(Index reserveSize) { m_data.reserve(reserveSize); } - /** \deprecated use insert() - */ - EIGEN_DEPRECATED Scalar& fill(Index row, Index col) - { - const Index outer = IsRowMajor ? row : col; - const Index inner = IsRowMajor ? col : row; - - if (m_outerIndex[outer+1]==0) - { - // we start a new inner vector - Index i = outer; - while (i>=0 && m_outerIndex[i]==0) - { - m_outerIndex[i] = m_data.size(); - --i; - } - m_outerIndex[outer+1] = m_outerIndex[outer]; - } - else - { - ei_assert(m_data.index(m_data.size()-1)<inner && "wrong sorted insertion"); - } -// std::cerr << size_t(m_outerIndex[outer+1]) << " == " << m_data.size() << "\n"; - assert(size_t(m_outerIndex[outer+1]) == m_data.size()); - Index id = m_outerIndex[outer+1]; - ++m_outerIndex[outer+1]; + //--- low level purely coherent filling --- - m_data.append(0, inner); - return m_data.value(id); + /** \returns a reference to the non zero coefficient at position \a row, \a col assuming that: + * - the nonzero does not already exist + * - the new coefficient is the last one according to the storage order + * + * Before filling a given inner vector you must call the statVec(Index) function. + * + * After an insertion session, you should call the finalize() function. + * + * \sa insert, insertBackByOuterInner, startVec */ + inline Scalar& insertBack(Index row, Index col) + { + return insertBackByOuterInner(IsRowMajor?row:col, IsRowMajor?col:row); } - //--- low level purely coherent filling --- - - inline Scalar& insertBack(Index outer, Index inner) + /** \sa insertBack, startVec */ + inline Scalar& insertBackByOuterInner(Index outer, Index inner) { - ei_assert(size_t(m_outerIndex[outer+1]) == m_data.size() && "wrong sorted insertion"); - ei_assert( (m_outerIndex[outer+1]-m_outerIndex[outer]==0 || m_data.index(m_data.size()-1)<inner) && "wrong sorted insertion"); + ei_assert(size_t(m_outerIndex[outer+1]) == m_data.size() && "Invalid ordered insertion (invalid outer index)"); + ei_assert( (m_outerIndex[outer+1]-m_outerIndex[outer]==0 || m_data.index(m_data.size()-1)<inner) && "Invalid ordered insertion (invalid inner index)"); Index id = m_outerIndex[outer+1]; ++m_outerIndex[outer+1]; m_data.append(0, inner); return m_data.value(id); } - inline Scalar& insertBackNoCheck(Index outer, Index inner) + /** \warning use it only if you know what you are doing */ + inline Scalar& insertBackByOuterInnerUnordered(Index outer, Index inner) { Index id = m_outerIndex[outer+1]; ++m_outerIndex[outer+1]; @@ -203,23 +179,16 @@ class SparseMatrix return m_data.value(id); } + /** \sa insertBack, insertBackByOuterInner */ inline void startVec(Index outer) { - ei_assert(m_outerIndex[outer]==int(m_data.size()) && "you must call startVec on each inner vec"); - ei_assert(m_outerIndex[outer+1]==0 && "you must call startVec on each inner vec"); + ei_assert(m_outerIndex[outer]==int(m_data.size()) && "You must call startVec for each inner vector sequentially"); + ei_assert(m_outerIndex[outer+1]==0 && "You must call startVec for each inner vector sequentially"); m_outerIndex[outer+1] = m_outerIndex[outer]; } //--- - /** \deprecated use insert() - * Like fill() but with random inner coordinates. - */ - EIGEN_DEPRECATED Scalar& fillrand(Index row, Index col) - { - return insert(row,col); - } - /** \returns a reference to a novel non zero coefficient with coordinates \a row x \a col. * The non zero coefficient must \b not already exist. * @@ -332,7 +301,8 @@ class SparseMatrix return (m_data.value(id) = 0); } - EIGEN_DEPRECATED void endFill() { finalize(); } + + /** Must be called after inserting a set of non zero entries. */ @@ -351,6 +321,7 @@ class SparseMatrix } } + /** Suppress all nonzeros which are smaller than \a reference under the tolerence \a epsilon */ void prune(Scalar reference, RealScalar epsilon = NumTraits<RealScalar>::dummy_precision()) { Index k = 0; @@ -389,23 +360,29 @@ class SparseMatrix } memset(m_outerIndex, 0, (m_outerSize+1)*sizeof(Index)); } + + /** Low level API + * Resize the nonzero vector to \a size */ void resizeNonZeros(Index size) { m_data.resize(size); } + /** Default constructor yielding an empty \c 0 \c x \c 0 matrix */ inline SparseMatrix() : m_outerSize(-1), m_innerSize(0), m_outerIndex(0) { resize(0, 0); } + /** Constructs a \a rows \c x \a cols empty matrix */ inline SparseMatrix(Index rows, Index cols) : m_outerSize(0), m_innerSize(0), m_outerIndex(0) { resize(rows, cols); } + /** Constructs a sparse matrix from the sparse expression \a other */ template<typename OtherDerived> inline SparseMatrix(const SparseMatrixBase<OtherDerived>& other) : m_outerSize(0), m_innerSize(0), m_outerIndex(0) @@ -413,12 +390,14 @@ class SparseMatrix *this = other.derived(); } + /** Copy constructor */ inline SparseMatrix(const SparseMatrix& other) : Base(), m_outerSize(0), m_innerSize(0), m_outerIndex(0) { *this = other.derived(); } + /** Swap the content of two sparse matrices of same type (optimization) */ inline void swap(SparseMatrix& other) { //EIGEN_DBG_SPARSE(std::cout << "SparseMatrix:: swap\n"); @@ -444,11 +423,13 @@ class SparseMatrix return *this; } + #ifndef EIGEN_PARSED_BY_DOXYGEN template<typename Lhs, typename Rhs> inline SparseMatrix& operator=(const SparseProduct<Lhs,Rhs>& product) { return Base::operator=(product); } + #endif template<typename OtherDerived> EIGEN_DONT_INLINE SparseMatrix& operator=(const SparseMatrixBase<OtherDerived>& other) @@ -534,10 +515,65 @@ class SparseMatrix /** Overloaded for performance */ Scalar sum() const; + + public: + + /** \deprecated use setZero() and reserve() + * Initializes the filling process of \c *this. + * \param reserveSize approximate number of nonzeros + * Note that the matrix \c *this is zero-ed. + */ + EIGEN_DEPRECATED void startFill(Index reserveSize = 1000) + { + setZero(); + m_data.reserve(reserveSize); + } + + /** \deprecated use insert() + * Like fill() but with random inner coordinates. + */ + EIGEN_DEPRECATED Scalar& fillrand(Index row, Index col) + { + return insert(row,col); + } + + /** \deprecated use insert() + */ + EIGEN_DEPRECATED Scalar& fill(Index row, Index col) + { + const Index outer = IsRowMajor ? row : col; + const Index inner = IsRowMajor ? col : row; + + if (m_outerIndex[outer+1]==0) + { + // we start a new inner vector + Index i = outer; + while (i>=0 && m_outerIndex[i]==0) + { + m_outerIndex[i] = m_data.size(); + --i; + } + m_outerIndex[outer+1] = m_outerIndex[outer]; + } + else + { + ei_assert(m_data.index(m_data.size()-1)<inner && "wrong sorted insertion"); + } +// std::cerr << size_t(m_outerIndex[outer+1]) << " == " << m_data.size() << "\n"; + assert(size_t(m_outerIndex[outer+1]) == m_data.size()); + Index id = m_outerIndex[outer+1]; + ++m_outerIndex[outer+1]; + + m_data.append(0, inner); + return m_data.value(id); + } + + /** \deprecated use finalize */ + EIGEN_DEPRECATED void endFill() { finalize(); } }; -template<typename Scalar, int _Options> -class SparseMatrix<Scalar,_Options>::InnerIterator +template<typename Scalar, int _Options, typename _Index> +class SparseMatrix<Scalar,_Options,_Index>::InnerIterator { public: InnerIterator(const SparseMatrix& mat, Index outer) diff --git a/Eigen/src/Sparse/SparseMatrixBase.h b/Eigen/src/Sparse/SparseMatrixBase.h index bafb09b1d..bde8868d5 100644 --- a/Eigen/src/Sparse/SparseMatrixBase.h +++ b/Eigen/src/Sparse/SparseMatrixBase.h @@ -43,7 +43,7 @@ template<typename Derived> class SparseMatrixBase : public EigenBase<Derived> typedef typename ei_traits<Derived>::Scalar Scalar; typedef typename ei_packet_traits<Scalar>::type PacketScalar; typedef typename ei_traits<Derived>::StorageKind StorageKind; - typedef typename ei_index<StorageKind>::type Index; + typedef typename ei_traits<Derived>::Index Index; typedef SparseMatrixBase StorageBaseType; @@ -209,7 +209,7 @@ template<typename Derived> class SparseMatrixBase : public EigenBase<Derived> { Scalar v = it.value(); if (v!=Scalar(0)) - temp.insertBack(Flip?it.index():j,Flip?j:it.index()) = v; + temp.insertBackByOuterInner(Flip?it.index():j,Flip?j:it.index()) = v; } } temp.finalize(); @@ -239,7 +239,7 @@ template<typename Derived> class SparseMatrixBase : public EigenBase<Derived> { Scalar v = it.value(); if (v!=Scalar(0)) - derived().insertBack(j,it.index()) = v; + derived().insertBackByOuterInner(j,it.index()) = v; } } derived().finalize(); diff --git a/Eigen/src/Sparse/SparseProduct.h b/Eigen/src/Sparse/SparseProduct.h index 548d48ed7..cf7544e87 100644 --- a/Eigen/src/Sparse/SparseProduct.h +++ b/Eigen/src/Sparse/SparseProduct.h @@ -57,6 +57,8 @@ struct ei_traits<SparseProduct<LhsNested, RhsNested> > typedef typename ei_cleantype<LhsNested>::type _LhsNested; typedef typename ei_cleantype<RhsNested>::type _RhsNested; typedef typename _LhsNested::Scalar Scalar; + typedef typename ei_promote_index_type<typename ei_traits<_LhsNested>::Index, + typename ei_traits<_RhsNested>::Index>::type Index; enum { LhsCoeffReadCost = _LhsNested::CoeffReadCost, @@ -236,7 +238,7 @@ static void ei_sparse_product_impl(const Lhs& lhs, const Rhs& rhs, ResultType& r ei_assert(lhs.outerSize() == rhs.innerSize()); // allocate a temporary buffer - AmbiVector<Scalar> tempVector(rows); + AmbiVector<Scalar,Index> tempVector(rows); // estimate the number of non zero entries float ratioLhs = float(lhs.nonZeros())/(float(lhs.rows())*float(lhs.cols())); @@ -264,8 +266,8 @@ static void ei_sparse_product_impl(const Lhs& lhs, const Rhs& rhs, ResultType& r } } res.startVec(j); - for (typename AmbiVector<Scalar>::Iterator it(tempVector); it; ++it) - res.insertBack(j,it.index()) = it.value(); + for (typename AmbiVector<Scalar,Index>::Iterator it(tempVector); it; ++it) + res.insertBackByOuterInner(j,it.index()) = it.value(); } res.finalize(); } @@ -380,9 +382,9 @@ struct ei_sparse_product_selector2<Lhs,Rhs,ResultType,RowMajor,ColMajor,ColMajor static void run(const Lhs& lhs, const Rhs& rhs, ResultType& res) { // prevent warnings until the code is fixed - (void) lhs; - (void) rhs; - (void) res; + EIGEN_UNUSED_VARIABLE(lhs); + EIGEN_UNUSED_VARIABLE(rhs); + EIGEN_UNUSED_VARIABLE(res); // typedef SparseMatrix<typename ResultType::Scalar,RowMajor> RowMajorMatrix; // RowMajorMatrix rhsRow = rhs; diff --git a/Eigen/src/Sparse/SparseRedux.h b/Eigen/src/Sparse/SparseRedux.h index ea2ce1870..241be6c2e 100644 --- a/Eigen/src/Sparse/SparseRedux.h +++ b/Eigen/src/Sparse/SparseRedux.h @@ -37,17 +37,17 @@ SparseMatrixBase<Derived>::sum() const return res; } -template<typename _Scalar, int _Options> -typename ei_traits<SparseMatrix<_Scalar,_Options> >::Scalar -SparseMatrix<_Scalar,_Options>::sum() const +template<typename _Scalar, int _Options, typename _Index> +typename ei_traits<SparseMatrix<_Scalar,_Options,_Index> >::Scalar +SparseMatrix<_Scalar,_Options,_Index>::sum() const { ei_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix"); return Matrix<Scalar,1,Dynamic>::Map(&m_data.value(0), m_data.size()).sum(); } -template<typename _Scalar, int _Options> -typename ei_traits<SparseVector<_Scalar,_Options> >::Scalar -SparseVector<_Scalar,_Options>::sum() const +template<typename _Scalar, int _Options, typename _Index> +typename ei_traits<SparseVector<_Scalar,_Options, _Index> >::Scalar +SparseVector<_Scalar,_Options,_Index>::sum() const { ei_assert(rows()>0 && cols()>0 && "you are using a non initialized matrix"); return Matrix<Scalar,1,Dynamic>::Map(&m_data.value(0), m_data.size()).sum(); diff --git a/Eigen/src/Sparse/SparseUtil.h b/Eigen/src/Sparse/SparseUtil.h index d94f5ce8c..f780f4087 100644 --- a/Eigen/src/Sparse/SparseUtil.h +++ b/Eigen/src/Sparse/SparseUtil.h @@ -56,30 +56,13 @@ EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(Derived, -=) \ EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, *=) \ EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, /=) -#define _EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(Derived, BaseClass) \ - typedef BaseClass Base; \ - typedef typename Eigen::ei_traits<Derived>::Scalar Scalar; \ - typedef typename Eigen::NumTraits<Scalar>::Real RealScalar; \ - typedef typename Eigen::ei_nested<Derived>::type Nested; \ - typedef typename Eigen::ei_traits<Derived>::StorageKind StorageKind; \ - typedef typename Eigen::ei_index<StorageKind>::type Index; \ - enum { RowsAtCompileTime = Eigen::ei_traits<Derived>::RowsAtCompileTime, \ - ColsAtCompileTime = Eigen::ei_traits<Derived>::ColsAtCompileTime, \ - Flags = Eigen::ei_traits<Derived>::Flags, \ - CoeffReadCost = Eigen::ei_traits<Derived>::CoeffReadCost, \ - SizeAtCompileTime = Base::SizeAtCompileTime, \ - IsVectorAtCompileTime = Base::IsVectorAtCompileTime }; - -#define EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(Derived) \ - _EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(Derived, Eigen::SparseMatrixBase<Derived>) - #define _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, BaseClass) \ typedef BaseClass Base; \ typedef typename Eigen::ei_traits<Derived>::Scalar Scalar; \ typedef typename Eigen::NumTraits<Scalar>::Real RealScalar; \ typedef typename Eigen::ei_nested<Derived>::type Nested; \ typedef typename Eigen::ei_traits<Derived>::StorageKind StorageKind; \ - typedef typename Eigen::ei_index<StorageKind>::type Index; \ + typedef typename Eigen::ei_traits<Derived>::Index Index; \ enum { RowsAtCompileTime = Eigen::ei_traits<Derived>::RowsAtCompileTime, \ ColsAtCompileTime = Eigen::ei_traits<Derived>::ColsAtCompileTime, \ Flags = Eigen::ei_traits<Derived>::Flags, \ @@ -92,12 +75,6 @@ EIGEN_SPARSE_INHERIT_SCALAR_ASSIGNMENT_OPERATOR(Derived, /=) #define EIGEN_SPARSE_PUBLIC_INTERFACE(Derived) \ _EIGEN_SPARSE_PUBLIC_INTERFACE(Derived, Eigen::SparseMatrixBase<Derived>) -template<> -struct ei_index<Sparse> -{ typedef EIGEN_DEFAULT_SPARSE_INDEX_TYPE type; }; - -typedef ei_index<Sparse>::type SparseIndex; - enum SparseBackend { DefaultBackend, Taucs, @@ -128,10 +105,10 @@ enum { }; template<typename Derived> class SparseMatrixBase; -template<typename _Scalar, int _Flags = 0> class SparseMatrix; -template<typename _Scalar, int _Flags = 0> class DynamicSparseMatrix; -template<typename _Scalar, int _Flags = 0> class SparseVector; -template<typename _Scalar, int _Flags = 0> class MappedSparseMatrix; +template<typename _Scalar, int _Flags = 0, typename _Index = int> class SparseMatrix; +template<typename _Scalar, int _Flags = 0, typename _Index = int> class DynamicSparseMatrix; +template<typename _Scalar, int _Flags = 0, typename _Index = int> class SparseVector; +template<typename _Scalar, int _Flags = 0, typename _Index = int> class MappedSparseMatrix; template<typename MatrixType, int Size> class SparseInnerVectorSet; template<typename MatrixType, int Mode> class SparseTriangularView; diff --git a/Eigen/src/Sparse/SparseVector.h b/Eigen/src/Sparse/SparseVector.h index 4013b4de5..dd81b749e 100644 --- a/Eigen/src/Sparse/SparseVector.h +++ b/Eigen/src/Sparse/SparseVector.h @@ -34,10 +34,11 @@ * See http://www.netlib.org/linalg/html_templates/node91.html for details on the storage scheme. * */ -template<typename _Scalar, int _Options> -struct ei_traits<SparseVector<_Scalar, _Options> > +template<typename _Scalar, int _Options, typename _Index> +struct ei_traits<SparseVector<_Scalar, _Options, _Index> > { typedef _Scalar Scalar; + typedef _Index Index; typedef Sparse StorageKind; typedef MatrixXpr XprKind; enum { @@ -53,12 +54,12 @@ struct ei_traits<SparseVector<_Scalar, _Options> > }; }; -template<typename _Scalar, int _Options> +template<typename _Scalar, int _Options, typename _Index> class SparseVector - : public SparseMatrixBase<SparseVector<_Scalar, _Options> > + : public SparseMatrixBase<SparseVector<_Scalar, _Options, _Index> > { public: - EIGEN_SPARSE_GENERIC_PUBLIC_INTERFACE(SparseVector) + EIGEN_SPARSE_PUBLIC_INTERFACE(SparseVector) EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseVector, +=) EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseVector, -=) // EIGEN_SPARSE_INHERIT_ASSIGNMENT_OPERATOR(SparseVector, =) @@ -69,11 +70,11 @@ class SparseVector typedef SparseMatrixBase<SparseVector> SparseBase; enum { IsColVector = ei_traits<SparseVector>::IsColVector }; - CompressedStorage<Scalar> m_data; + CompressedStorage<Scalar,Index> m_data; Index m_size; - CompressedStorage<Scalar>& _data() { return m_data; } - CompressedStorage<Scalar>& _data() const { return m_data; } + CompressedStorage<Scalar,Index>& _data() { return m_data; } + CompressedStorage<Scalar,Index>& _data() const { return m_data; } public: @@ -127,7 +128,7 @@ class SparseVector ei_assert(outer==0); } - inline Scalar& insertBack(Index outer, Index inner) + inline Scalar& insertBackByOuterInner(Index outer, Index inner) { ei_assert(outer==0); return insertBack(inner); @@ -138,8 +139,10 @@ class SparseVector return m_data.value(m_data.size()-1); } - inline Scalar& insert(Index outer, Index inner) + inline Scalar& insert(Index row, Index col) { + Index inner = IsColVector ? row : col; + Index outer = IsColVector ? col : row; ei_assert(outer==0); return insert(inner); } @@ -165,42 +168,7 @@ class SparseVector */ inline void reserve(Index reserveSize) { m_data.reserve(reserveSize); } - /** \deprecated use setZero() and reserve() */ - EIGEN_DEPRECATED void startFill(Index reserve) - { - setZero(); - m_data.reserve(reserve); - } - /** \deprecated use insertBack(Index,Index) */ - EIGEN_DEPRECATED Scalar& fill(Index r, Index c) - { - ei_assert(r==0 || c==0); - return fill(IsColVector ? r : c); - } - - /** \deprecated use insertBack(Index) */ - EIGEN_DEPRECATED Scalar& fill(Index i) - { - m_data.append(0, i); - return m_data.value(m_data.size()-1); - } - - /** \deprecated use insert(Index,Index) */ - EIGEN_DEPRECATED Scalar& fillrand(Index r, Index c) - { - ei_assert(r==0 || c==0); - return fillrand(IsColVector ? r : c); - } - - /** \deprecated use insert(Index) */ - EIGEN_DEPRECATED Scalar& fillrand(Index i) - { - return insert(i); - } - - /** \deprecated use finalize() */ - EIGEN_DEPRECATED void endFill() {} inline void finalize() {} void prune(Scalar reference, RealScalar epsilon = NumTraits<RealScalar>::dummy_precision()) @@ -362,10 +330,49 @@ class SparseVector /** Overloaded for performance */ Scalar sum() const; + + public: + + /** \deprecated use setZero() and reserve() */ + EIGEN_DEPRECATED void startFill(Index reserve) + { + setZero(); + m_data.reserve(reserve); + } + + /** \deprecated use insertBack(Index,Index) */ + EIGEN_DEPRECATED Scalar& fill(Index r, Index c) + { + ei_assert(r==0 || c==0); + return fill(IsColVector ? r : c); + } + + /** \deprecated use insertBack(Index) */ + EIGEN_DEPRECATED Scalar& fill(Index i) + { + m_data.append(0, i); + return m_data.value(m_data.size()-1); + } + + /** \deprecated use insert(Index,Index) */ + EIGEN_DEPRECATED Scalar& fillrand(Index r, Index c) + { + ei_assert(r==0 || c==0); + return fillrand(IsColVector ? r : c); + } + + /** \deprecated use insert(Index) */ + EIGEN_DEPRECATED Scalar& fillrand(Index i) + { + return insert(i); + } + + /** \deprecated use finalize() */ + EIGEN_DEPRECATED void endFill() {} }; -template<typename Scalar, int _Options> -class SparseVector<Scalar,_Options>::InnerIterator +template<typename Scalar, int _Options, typename _Index> +class SparseVector<Scalar,_Options,_Index>::InnerIterator { public: InnerIterator(const SparseVector& vec, Index outer=0) @@ -374,7 +381,7 @@ class SparseVector<Scalar,_Options>::InnerIterator ei_assert(outer==0); } - InnerIterator(const CompressedStorage<Scalar>& data) + InnerIterator(const CompressedStorage<Scalar,Index>& data) : m_data(data), m_id(0), m_end(static_cast<Index>(m_data.size())) {} @@ -395,7 +402,7 @@ class SparseVector<Scalar,_Options>::InnerIterator inline operator bool() const { return (m_id < m_end); } protected: - const CompressedStorage<Scalar>& m_data; + const CompressedStorage<Scalar,Index>& m_data; Index m_id; const Index m_end; }; diff --git a/Eigen/src/Sparse/SuperLUSupport.h b/Eigen/src/Sparse/SuperLUSupport.h index 18a967539..d93f69df8 100644 --- a/Eigen/src/Sparse/SuperLUSupport.h +++ b/Eigen/src/Sparse/SuperLUSupport.h @@ -267,8 +267,8 @@ SluMatrix SparseMatrixBase<Derived>::asSluMatrix() } /** View a Super LU matrix as an Eigen expression */ -template<typename Scalar, int Flags> -MappedSparseMatrix<Scalar,Flags>::MappedSparseMatrix(SluMatrix& sluMat) +template<typename Scalar, int Flags, typename _Index> +MappedSparseMatrix<Scalar,Flags,_Index>::MappedSparseMatrix(SluMatrix& sluMat) { if ((Flags&RowMajorBit)==RowMajorBit) { diff --git a/Eigen/src/Sparse/TaucsSupport.h b/Eigen/src/Sparse/TaucsSupport.h index 2a1963f5b..c189e0127 100644 --- a/Eigen/src/Sparse/TaucsSupport.h +++ b/Eigen/src/Sparse/TaucsSupport.h @@ -63,8 +63,8 @@ taucs_ccs_matrix SparseMatrixBase<Derived>::asTaucsMatrix() return res; } -template<typename Scalar, int Flags> -MappedSparseMatrix<Scalar,Flags>::MappedSparseMatrix(taucs_ccs_matrix& taucsMat) +template<typename Scalar, int Flags, typename _Index> +MappedSparseMatrix<Scalar,Flags,_Index>::MappedSparseMatrix(taucs_ccs_matrix& taucsMat) { m_innerSize = taucsMat.m; m_outerSize = taucsMat.n; diff --git a/Eigen/src/Sparse/TriangularSolver.h b/Eigen/src/Sparse/TriangularSolver.h index 039424bf0..7528ba534 100644 --- a/Eigen/src/Sparse/TriangularSolver.h +++ b/Eigen/src/Sparse/TriangularSolver.h @@ -207,10 +207,12 @@ template<typename Lhs, typename Rhs, int Mode, int UpLo> struct ei_sparse_solve_triangular_sparse_selector<Lhs,Rhs,Mode,UpLo,ColMajor> { typedef typename Rhs::Scalar Scalar; + typedef typename ei_promote_index_type<typename ei_traits<Lhs>::Index, + typename ei_traits<Rhs>::Index>::type Index; static void run(const Lhs& lhs, Rhs& other) { const bool IsLower = (UpLo==Lower); - AmbiVector<Scalar> tempVector(other.rows()*2); + AmbiVector<Scalar,Index> tempVector(other.rows()*2); tempVector.setBounds(0,other.rows()); Rhs res(other.rows(), other.cols()); @@ -266,7 +268,7 @@ struct ei_sparse_solve_triangular_sparse_selector<Lhs,Rhs,Mode,UpLo,ColMajor> int count = 0; // FIXME compute a reference value to filter zeros - for (typename AmbiVector<Scalar>::Iterator it(tempVector/*,1e-12*/); it; ++it) + for (typename AmbiVector<Scalar,Index>::Iterator it(tempVector/*,1e-12*/); it; ++it) { ++ count; // std::cerr << "fill " << it.index() << ", " << col << "\n"; diff --git a/bench/BenchTimer.h b/bench/BenchTimer.h index 0a0a5e154..567064360 100644 --- a/bench/BenchTimer.h +++ b/bench/BenchTimer.h @@ -87,7 +87,12 @@ public: { m_times[CPU_TIMER] = getCpuTime() - m_starts[CPU_TIMER]; m_times[REAL_TIMER] = getRealTime() - m_starts[REAL_TIMER]; + #if EIGEN_VERSION_AT_LEAST(2,90,0) m_bests = m_bests.cwiseMin(m_times); + #else + m_bests(0) = std::min(m_bests(0),m_times(0)); + m_bests(1) = std::min(m_bests(1),m_times(1)); + #endif m_totals += m_times; } diff --git a/bench/bench_gemm.cpp b/bench/bench_gemm.cpp index 5c55d4b7c..77cc420f4 100644 --- a/bench/bench_gemm.cpp +++ b/bench/bench_gemm.cpp @@ -112,7 +112,8 @@ int main(int argc, char ** argv) if(procs>1) { BenchTimer tmono; - omp_set_num_threads(1); + //omp_set_num_threads(1); + Eigen::setNbThreads(1); BENCH(tmono, tries, rep, gemm(a,b,c)); std::cout << "eigen mono cpu " << tmono.best(CPU_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/tmono.best(CPU_TIMER))*1e-9 << " GFLOPS \t(" << tmono.total(CPU_TIMER) << "s)\n"; std::cout << "eigen mono real " << tmono.best(REAL_TIMER)/rep << "s \t" << (double(m)*n*p*rep*2/tmono.best(REAL_TIMER))*1e-9 << " GFLOPS \t(" << tmono.total(REAL_TIMER) << "s)\n"; diff --git a/doc/C07_TutorialSparse.dox b/doc/C07_TutorialSparse.dox index ae96d77c4..ee8a1a100 100644 --- a/doc/C07_TutorialSparse.dox +++ b/doc/C07_TutorialSparse.dox @@ -183,7 +183,7 @@ for(int j=0; j<1000; ++j) } mat.finalize(); // optional for a DynamicSparseMatrix \endcode - +Note that there also exist the insertBackByOuterInner(Index outer, Index, inner) function which allows to write code agnostic to the storage order. \section TutorialSparseFeatureSet Supported operators and functions diff --git a/doc/snippets/ComplexEigenSolver_eigenvalues.cpp b/doc/snippets/ComplexEigenSolver_eigenvalues.cpp index 1afa8b086..5509bd897 100644 --- a/doc/snippets/ComplexEigenSolver_eigenvalues.cpp +++ b/doc/snippets/ComplexEigenSolver_eigenvalues.cpp @@ -1,4 +1,4 @@ MatrixXcf ones = MatrixXcf::Ones(3,3); -ComplexEigenSolver<MatrixXcf> ces(ones); +ComplexEigenSolver<MatrixXcf> ces(ones, /* computeEigenvectors = */ false); cout << "The eigenvalues of the 3x3 matrix of ones are:" << endl << ces.eigenvalues() << endl; diff --git a/doc/snippets/EigenSolver_compute.cpp b/doc/snippets/EigenSolver_compute.cpp index 06138f608..a5c96e9b4 100644 --- a/doc/snippets/EigenSolver_compute.cpp +++ b/doc/snippets/EigenSolver_compute.cpp @@ -1,6 +1,6 @@ EigenSolver<MatrixXf> es; MatrixXf A = MatrixXf::Random(4,4); -es.compute(A); +es.compute(A, /* computeEigenvectors = */ false); cout << "The eigenvalues of A are: " << es.eigenvalues().transpose() << endl; -es.compute(A + MatrixXf::Identity(4,4)); // re-use es to compute eigenvalues of A+I +es.compute(A + MatrixXf::Identity(4,4), false); // re-use es to compute eigenvalues of A+I cout << "The eigenvalues of A+I are: " << es.eigenvalues().transpose() << endl; diff --git a/doc/snippets/EigenSolver_eigenvalues.cpp b/doc/snippets/EigenSolver_eigenvalues.cpp index 8d83ea982..ed28869a0 100644 --- a/doc/snippets/EigenSolver_eigenvalues.cpp +++ b/doc/snippets/EigenSolver_eigenvalues.cpp @@ -1,4 +1,4 @@ MatrixXd ones = MatrixXd::Ones(3,3); -EigenSolver<MatrixXd> es(ones); +EigenSolver<MatrixXd> es(ones, false); cout << "The eigenvalues of the 3x3 matrix of ones are:" << endl << es.eigenvalues() << endl; diff --git a/doc/snippets/RealSchur_compute.cpp b/doc/snippets/RealSchur_compute.cpp index 4dcfaf0f2..20c2611b8 100644 --- a/doc/snippets/RealSchur_compute.cpp +++ b/doc/snippets/RealSchur_compute.cpp @@ -1,6 +1,6 @@ MatrixXf A = MatrixXf::Random(4,4); RealSchur<MatrixXf> schur(4); -schur.compute(A); +schur.compute(A, /* computeU = */ false); cout << "The matrix T in the decomposition of A is:" << endl << schur.matrixT() << endl; -schur.compute(A.inverse()); +schur.compute(A.inverse(), /* computeU = */ false); cout << "The matrix T in the decomposition of A^(-1) is:" << endl << schur.matrixT() << endl; diff --git a/test/array.cpp b/test/array.cpp index df1e1b49e..b1fa45b12 100644 --- a/test/array.cpp +++ b/test/array.cpp @@ -129,7 +129,7 @@ template<typename ArrayType> void comparisons(const ArrayType& m) VERIFY(((m1.abs()+1)>RealScalar(0.1)).count() == rows*cols); typedef Array<typename ArrayType::Index, Dynamic, 1> ArrayOfIndices; - + // TODO allows colwise/rowwise for array VERIFY_IS_APPROX(((m1.abs()+1)>RealScalar(0.1)).colwise().count(), ArrayOfIndices::Constant(cols,rows).transpose()); VERIFY_IS_APPROX(((m1.abs()+1)>RealScalar(0.1)).rowwise().count(), ArrayOfIndices::Constant(rows, cols)); @@ -151,10 +151,10 @@ template<typename ArrayType> void array_real(const ArrayType& m) VERIFY_IS_APPROX(m1.sin(), ei_sin(m1)); VERIFY_IS_APPROX(m1.cos(), std::cos(m1)); VERIFY_IS_APPROX(m1.cos(), ei_cos(m1)); - + VERIFY_IS_APPROX(ei_cos(m1+RealScalar(3)*m2), ei_cos((m1+RealScalar(3)*m2).eval())); VERIFY_IS_APPROX(std::cos(m1+RealScalar(3)*m2), std::cos((m1+RealScalar(3)*m2).eval())); - + VERIFY_IS_APPROX(m1.abs().sqrt(), std::sqrt(std::abs(m1))); VERIFY_IS_APPROX(m1.abs().sqrt(), ei_sqrt(ei_abs(m1))); VERIFY_IS_APPROX(m1.abs(), ei_sqrt(ei_abs2(m1))); @@ -163,10 +163,10 @@ template<typename ArrayType> void array_real(const ArrayType& m) VERIFY_IS_APPROX(ei_abs2(std::real(m1)) + ei_abs2(std::imag(m1)), ei_abs2(m1)); if(!NumTraits<Scalar>::IsComplex) VERIFY_IS_APPROX(ei_real(m1), m1); - + VERIFY_IS_APPROX(m1.abs().log(), std::log(std::abs(m1))); VERIFY_IS_APPROX(m1.abs().log(), ei_log(ei_abs(m1))); - + VERIFY_IS_APPROX(m1.exp(), std::exp(m1)); VERIFY_IS_APPROX(m1.exp() * m2.exp(), std::exp(m1+m2)); VERIFY_IS_APPROX(m1.exp(), ei_exp(m1)); diff --git a/test/array_for_matrix.cpp b/test/array_for_matrix.cpp index 477d1788d..5d0b9bbbd 100644 --- a/test/array_for_matrix.cpp +++ b/test/array_for_matrix.cpp @@ -37,10 +37,10 @@ template<typename MatrixType> void array_for_matrix(const MatrixType& m) MatrixType m1 = MatrixType::Random(rows, cols), m2 = MatrixType::Random(rows, cols), m3(rows, cols); - + ColVectorType cv1 = ColVectorType::Random(rows); RowVectorType rv1 = RowVectorType::Random(cols); - + Scalar s1 = ei_random<Scalar>(), s2 = ei_random<Scalar>(); diff --git a/test/array_reverse.cpp b/test/array_reverse.cpp index ccf8dcc87..3933ff523 100644 --- a/test/array_reverse.cpp +++ b/test/array_reverse.cpp @@ -103,47 +103,6 @@ template<typename MatrixType> void reverse(const MatrixType& m) } } - /* - cout << "m1:" << endl << m1 << endl; - cout << "m1c_reversed:" << endl << m1c_reversed << endl; - - cout << "----------------" << endl; - - for ( int i=0; i< rows*cols; i++){ - cout << m1c_reversed.coeff(i) << endl; - } - - cout << "----------------" << endl; - - for ( int i=0; i< rows*cols; i++){ - cout << m1c_reversed.colwise().reverse().coeff(i) << endl; - } - - cout << "================" << endl; - - cout << "m1.coeff( ind ): " << m1.coeff( ind ) << endl; - cout << "m1c_reversed.colwise().reverse().coeff( ind ): " << m1c_reversed.colwise().reverse().coeff( ind ) << endl; - */ - - //MatrixType m1r_reversed = m1.rowwise().reverse(); - //VERIFY_IS_APPROX( m1r_reversed.rowwise().reverse().coeff( ind ), m1.coeff( ind ) ); - - /* - cout << "m1" << endl << m1 << endl; - cout << "m1 using coeff(int index)" << endl; - for ( int i = 0; i < rows*cols; i++) { - cout << m1.coeff(i) << " "; - } - cout << endl; - - cout << "m1.transpose()" << endl << m1.transpose() << endl; - cout << "m1.transpose() using coeff(int index)" << endl; - for ( int i = 0; i < rows*cols; i++) { - cout << m1.transpose().coeff(i) << " "; - } - cout << endl; - */ - /* Scalar x = ei_random<Scalar>(); int r = ei_random<int>(0, rows-1), @@ -152,6 +111,7 @@ template<typename MatrixType> void reverse(const MatrixType& m) m1.reverse()(r, c) = x; VERIFY_IS_APPROX(x, m1(rows - 1 - r, cols - 1 - c)); + /* m1.colwise().reverse()(r, c) = x; VERIFY_IS_APPROX(x, m1(rows - 1 - r, c)); diff --git a/test/basicstuff.cpp b/test/basicstuff.cpp index 53b503f46..ddddb5985 100644 --- a/test/basicstuff.cpp +++ b/test/basicstuff.cpp @@ -138,7 +138,8 @@ template<typename MatrixType> void basicStuffComplex(const MatrixType& m) VERIFY(ei_imag(s1)==ei_imag_ref(s1)); ei_real_ref(s1) = ei_real(s2); ei_imag_ref(s1) = ei_imag(s2); - VERIFY(s1==s2); + VERIFY(ei_isApprox(s1, s2, NumTraits<RealScalar>::epsilon())); + // extended precision in Intel FPUs means that s1 == s2 in the line above is not guaranteed. RealMatrixType rm1 = RealMatrixType::Random(rows,cols), rm2 = RealMatrixType::Random(rows,cols); diff --git a/test/cholesky.cpp b/test/cholesky.cpp index 0ae26c7d5..666cee20f 100644 --- a/test/cholesky.cpp +++ b/test/cholesky.cpp @@ -26,10 +26,21 @@ #define EIGEN_NO_ASSERTION_CHECKING #endif +static int nb_temporaries; + +#define EIGEN_DEBUG_MATRIX_CTOR { if(size!=0) nb_temporaries++; } + #include "main.h" #include <Eigen/Cholesky> #include <Eigen/QR> +#define VERIFY_EVALUATION_COUNT(XPR,N) {\ + nb_temporaries = 0; \ + XPR; \ + if(nb_temporaries!=N) std::cerr << "nb_temporaries == " << nb_temporaries << "\n"; \ + VERIFY( (#XPR) && nb_temporaries==N ); \ + } + #ifdef HAS_GSL #include "gsl_helper.h" #endif @@ -110,20 +121,46 @@ template<typename MatrixType> void cholesky(const MatrixType& m) VERIFY_IS_APPROX(symm * matX, matB); } - int sign = ei_random<int>()%2 ? 1 : -1; - - if(sign == -1) + // LDLT { - symm = -symm; // test a negative matrix - } + int sign = ei_random<int>()%2 ? 1 : -1; - { - LDLT<SquareMatrixType> ldlt(symm); - VERIFY_IS_APPROX(symm, ldlt.reconstructedMatrix()); - vecX = ldlt.solve(vecB); + if(sign == -1) + { + symm = -symm; // test a negative matrix + } + + SquareMatrixType symmUp = symm.template triangularView<Upper>(); + SquareMatrixType symmLo = symm.template triangularView<Lower>(); + + LDLT<SquareMatrixType,Lower> ldltlo(symmLo); + VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix()); + vecX = ldltlo.solve(vecB); + VERIFY_IS_APPROX(symm * vecX, vecB); + matX = ldltlo.solve(matB); + VERIFY_IS_APPROX(symm * matX, matB); + + LDLT<SquareMatrixType,Upper> ldltup(symmUp); + VERIFY_IS_APPROX(symm, ldltup.reconstructedMatrix()); + vecX = ldltup.solve(vecB); VERIFY_IS_APPROX(symm * vecX, vecB); - matX = ldlt.solve(matB); + matX = ldltup.solve(matB); VERIFY_IS_APPROX(symm * matX, matB); + + if(MatrixType::RowsAtCompileTime==Dynamic) + { + // note : each inplace permutation requires a small temporary vector (mask) + + // check inplace solve + matX = matB; + VERIFY_EVALUATION_COUNT(matX = ldltlo.solve(matX), 0); + VERIFY_IS_APPROX(matX, ldltlo.solve(matB).eval()); + + + matX = matB; + VERIFY_EVALUATION_COUNT(matX = ldltup.solve(matX), 0); + VERIFY_IS_APPROX(matX, ldltup.solve(matB).eval()); + } } } @@ -134,6 +171,7 @@ template<typename MatrixType> void cholesky_verify_assert() LLT<MatrixType> llt; VERIFY_RAISES_ASSERT(llt.matrixL()) + VERIFY_RAISES_ASSERT(llt.matrixU()) VERIFY_RAISES_ASSERT(llt.solve(tmp)) VERIFY_RAISES_ASSERT(llt.solveInPlace(&tmp)) diff --git a/test/eigensolver_complex.cpp b/test/eigensolver_complex.cpp index 5c5d7b38f..1c1dd98f3 100644 --- a/test/eigensolver_complex.cpp +++ b/test/eigensolver_complex.cpp @@ -2,6 +2,7 @@ // for linear algebra. Eigen itself is part of the KDE project. // // Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr> +// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk> // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -23,6 +24,7 @@ // Eigen. If not, see <http://www.gnu.org/licenses/>. #include "main.h" +#include <limits> #include <Eigen/Eigenvalues> #include <Eigen/LU> @@ -31,12 +33,14 @@ template<typename VectorType> void verify_is_approx_upto_permutation(const VectorType& vec1, const VectorType& vec2) { + typedef typename NumTraits<typename VectorType::Scalar>::Real RealScalar; + VERIFY(vec1.cols() == 1); VERIFY(vec2.cols() == 1); VERIFY(vec1.rows() == vec2.rows()); for (int k = 1; k <= vec1.rows(); ++k) { - VERIFY_IS_APPROX(vec1.array().pow(k).sum(), vec2.array().pow(k).sum()); + VERIFY_IS_APPROX(vec1.array().pow(RealScalar(k)).sum(), vec2.array().pow(RealScalar(k)).sum()); } } @@ -59,14 +63,20 @@ template<typename MatrixType> void eigensolver(const MatrixType& m) MatrixType symmA = a.adjoint() * a; ComplexEigenSolver<MatrixType> ei0(symmA); + VERIFY_IS_EQUAL(ei0.info(), Success); VERIFY_IS_APPROX(symmA * ei0.eigenvectors(), ei0.eigenvectors() * ei0.eigenvalues().asDiagonal()); ComplexEigenSolver<MatrixType> ei1(a); + VERIFY_IS_EQUAL(ei1.info(), Success); VERIFY_IS_APPROX(a * ei1.eigenvectors(), ei1.eigenvectors() * ei1.eigenvalues().asDiagonal()); // Note: If MatrixType is real then a.eigenvalues() uses EigenSolver and thus // another algorithm so results may differ slightly verify_is_approx_upto_permutation(a.eigenvalues(), ei1.eigenvalues()); - + + ComplexEigenSolver<MatrixType> eiNoEivecs(a, false); + VERIFY_IS_EQUAL(eiNoEivecs.info(), Success); + VERIFY_IS_APPROX(ei1.eigenvalues(), eiNoEivecs.eigenvalues()); + // Regression test for issue #66 MatrixType z = MatrixType::Zero(rows,cols); ComplexEigenSolver<MatrixType> eiz(z); @@ -74,6 +84,25 @@ template<typename MatrixType> void eigensolver(const MatrixType& m) MatrixType id = MatrixType::Identity(rows, cols); VERIFY_IS_APPROX(id.operatorNorm(), RealScalar(1)); + + if (rows > 1) + { + // Test matrix with NaN + a(0,0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN(); + ComplexEigenSolver<MatrixType> eiNaN(a); + VERIFY_IS_EQUAL(eiNaN.info(), NoConvergence); + } +} + +template<typename MatrixType> void eigensolver_verify_assert(const MatrixType& m) +{ + ComplexEigenSolver<MatrixType> eig; + VERIFY_RAISES_ASSERT(eig.eigenvectors()); + VERIFY_RAISES_ASSERT(eig.eigenvalues()); + + MatrixType a = MatrixType::Random(m.rows(),m.cols()); + eig.compute(a, false); + VERIFY_RAISES_ASSERT(eig.eigenvectors()); } void test_eigensolver_complex() @@ -85,6 +114,11 @@ void test_eigensolver_complex() CALL_SUBTEST_4( eigensolver(Matrix3f()) ); } + CALL_SUBTEST_1( eigensolver_verify_assert(Matrix4cf()) ); + CALL_SUBTEST_2( eigensolver_verify_assert(MatrixXcd(14,14)) ); + CALL_SUBTEST_3( eigensolver_verify_assert(Matrix<std::complex<float>, 1, 1>()) ); + CALL_SUBTEST_4( eigensolver_verify_assert(Matrix3f()) ); + // Test problem size constructors CALL_SUBTEST_5(ComplexEigenSolver<MatrixXf>(10)); } diff --git a/test/eigensolver_generic.cpp b/test/eigensolver_generic.cpp index d70f37ea4..92741a35c 100644 --- a/test/eigensolver_generic.cpp +++ b/test/eigensolver_generic.cpp @@ -2,6 +2,7 @@ // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr> +// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk> // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -23,6 +24,7 @@ // Eigen. If not, see <http://www.gnu.org/licenses/>. #include "main.h" +#include <limits> #include <Eigen/Eigenvalues> #ifdef HAS_GSL @@ -43,36 +45,52 @@ template<typename MatrixType> void eigensolver(const MatrixType& m) typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType; typedef typename std::complex<typename NumTraits<typename MatrixType::Scalar>::Real> Complex; - // RealScalar largerEps = 10*test_precision<RealScalar>(); - MatrixType a = MatrixType::Random(rows,cols); MatrixType a1 = MatrixType::Random(rows,cols); MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1; EigenSolver<MatrixType> ei0(symmA); + VERIFY_IS_EQUAL(ei0.info(), Success); VERIFY_IS_APPROX(symmA * ei0.pseudoEigenvectors(), ei0.pseudoEigenvectors() * ei0.pseudoEigenvalueMatrix()); VERIFY_IS_APPROX((symmA.template cast<Complex>()) * (ei0.pseudoEigenvectors().template cast<Complex>()), (ei0.pseudoEigenvectors().template cast<Complex>()) * (ei0.eigenvalues().asDiagonal())); EigenSolver<MatrixType> ei1(a); + VERIFY_IS_EQUAL(ei1.info(), Success); VERIFY_IS_APPROX(a * ei1.pseudoEigenvectors(), ei1.pseudoEigenvectors() * ei1.pseudoEigenvalueMatrix()); VERIFY_IS_APPROX(a.template cast<Complex>() * ei1.eigenvectors(), ei1.eigenvectors() * ei1.eigenvalues().asDiagonal()); VERIFY_IS_APPROX(a.eigenvalues(), ei1.eigenvalues()); + EigenSolver<MatrixType> eiNoEivecs(a, false); + VERIFY_IS_EQUAL(eiNoEivecs.info(), Success); + VERIFY_IS_APPROX(ei1.eigenvalues(), eiNoEivecs.eigenvalues()); + VERIFY_IS_APPROX(ei1.pseudoEigenvalueMatrix(), eiNoEivecs.pseudoEigenvalueMatrix()); + MatrixType id = MatrixType::Identity(rows, cols); VERIFY_IS_APPROX(id.operatorNorm(), RealScalar(1)); + + if (rows > 2) + { + // Test matrix with NaN + a(0,0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN(); + EigenSolver<MatrixType> eiNaN(a); + VERIFY_IS_EQUAL(eiNaN.info(), NoConvergence); + } } -template<typename MatrixType> void eigensolver_verify_assert() +template<typename MatrixType> void eigensolver_verify_assert(const MatrixType& m) { - MatrixType tmp; - EigenSolver<MatrixType> eig; - VERIFY_RAISES_ASSERT(eig.eigenvectors()) - VERIFY_RAISES_ASSERT(eig.pseudoEigenvectors()) - VERIFY_RAISES_ASSERT(eig.pseudoEigenvalueMatrix()) - VERIFY_RAISES_ASSERT(eig.eigenvalues()) + VERIFY_RAISES_ASSERT(eig.eigenvectors()); + VERIFY_RAISES_ASSERT(eig.pseudoEigenvectors()); + VERIFY_RAISES_ASSERT(eig.pseudoEigenvalueMatrix()); + VERIFY_RAISES_ASSERT(eig.eigenvalues()); + + MatrixType a = MatrixType::Random(m.rows(),m.cols()); + eig.compute(a, false); + VERIFY_RAISES_ASSERT(eig.eigenvectors()); + VERIFY_RAISES_ASSERT(eig.pseudoEigenvectors()); } void test_eigensolver_generic() @@ -88,11 +106,11 @@ void test_eigensolver_generic() CALL_SUBTEST_4( eigensolver(Matrix2d()) ); } - CALL_SUBTEST_1( eigensolver_verify_assert<Matrix4f>() ); - CALL_SUBTEST_2( eigensolver_verify_assert<MatrixXd>() ); - CALL_SUBTEST_4( eigensolver_verify_assert<Matrix2d>() ); - CALL_SUBTEST_5( eigensolver_verify_assert<MatrixXf>() ); + CALL_SUBTEST_1( eigensolver_verify_assert(Matrix4f()) ); + CALL_SUBTEST_2( eigensolver_verify_assert(MatrixXd(17,17)) ); + CALL_SUBTEST_3( eigensolver_verify_assert(Matrix<double,1,1>()) ); + CALL_SUBTEST_4( eigensolver_verify_assert(Matrix2d()) ); // Test problem size constructors - CALL_SUBTEST_6(EigenSolver<MatrixXf>(10)); + CALL_SUBTEST_5(EigenSolver<MatrixXf>(10)); } diff --git a/test/eigensolver_selfadjoint.cpp b/test/eigensolver_selfadjoint.cpp index 25ef280a1..2c2d5c985 100644 --- a/test/eigensolver_selfadjoint.cpp +++ b/test/eigensolver_selfadjoint.cpp @@ -2,6 +2,7 @@ // for linear algebra. // // Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr> +// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk> // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -23,6 +24,7 @@ // Eigen. If not, see <http://www.gnu.org/licenses/>. #include "main.h" +#include <limits> #include <Eigen/Eigenvalues> #ifdef HAS_GSL @@ -48,10 +50,12 @@ template<typename MatrixType> void selfadjointeigensolver(const MatrixType& m) MatrixType a = MatrixType::Random(rows,cols); MatrixType a1 = MatrixType::Random(rows,cols); MatrixType symmA = a.adjoint() * a + a1.adjoint() * a1; + symmA.template triangularView<StrictlyUpper>().setZero(); MatrixType b = MatrixType::Random(rows,cols); MatrixType b1 = MatrixType::Random(rows,cols); MatrixType symmB = b.adjoint() * b + b1.adjoint() * b1; + symmB.template triangularView<StrictlyUpper>().setZero(); SelfAdjointEigenSolver<MatrixType> eiSymm(symmA); // generalized eigen pb @@ -60,6 +64,9 @@ template<typename MatrixType> void selfadjointeigensolver(const MatrixType& m) #ifdef HAS_GSL if (ei_is_same_type<RealScalar,double>::ret) { + // restore symmA and symmB. + symmA = MatrixType(symmA.template selfadjointView<Lower>()); + symmB = MatrixType(symmB.template selfadjointView<Lower>()); typedef GslTraits<Scalar> Gsl; typename Gsl::Matrix gEvec=0, gSymmA=0, gSymmB=0; typename GslTraits<RealScalar>::Vector gEval=0; @@ -89,10 +96,9 @@ template<typename MatrixType> void selfadjointeigensolver(const MatrixType& m) VERIFY((symmA * _evec).isApprox(symmB * (_evec * _eval.asDiagonal()), largerEps)); // compare with eigen -// std::cerr << _eval.transpose() << "\n" << eiSymmGen.eigenvalues().transpose() << "\n\n"; -// std::cerr << _evec.format(6) << "\n\n" << eiSymmGen.eigenvectors().format(6) << "\n\n\n"; + MatrixType normalized_eivec = eiSymmGen.eigenvectors()*eiSymmGen.eigenvectors().colwise().norm().asDiagonal().inverse(); VERIFY_IS_APPROX(_eval, eiSymmGen.eigenvalues()); - VERIFY_IS_APPROX(_evec.cwiseAbs(), eiSymmGen.eigenvectors().cwiseAbs()); + VERIFY_IS_APPROX(_evec.cwiseAbs(), normalized_eivec.cwiseAbs()); Gsl::free(gSymmA); Gsl::free(gSymmB); @@ -101,20 +107,46 @@ template<typename MatrixType> void selfadjointeigensolver(const MatrixType& m) } #endif - VERIFY((symmA * eiSymm.eigenvectors()).isApprox( + VERIFY_IS_EQUAL(eiSymm.info(), Success); + VERIFY((symmA.template selfadjointView<Lower>() * eiSymm.eigenvectors()).isApprox( eiSymm.eigenvectors() * eiSymm.eigenvalues().asDiagonal(), largerEps)); VERIFY_IS_APPROX(symmA.template selfadjointView<Lower>().eigenvalues(), eiSymm.eigenvalues()); + SelfAdjointEigenSolver<MatrixType> eiSymmNoEivecs(symmA, false); + VERIFY_IS_EQUAL(eiSymmNoEivecs.info(), Success); + VERIFY_IS_APPROX(eiSymm.eigenvalues(), eiSymmNoEivecs.eigenvalues()); + // generalized eigen problem Ax = lBx - VERIFY((symmA * eiSymmGen.eigenvectors()).isApprox( - symmB * (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps)); + VERIFY_IS_EQUAL(eiSymmGen.info(), Success); + VERIFY((symmA.template selfadjointView<Lower>() * eiSymmGen.eigenvectors()).isApprox( + symmB.template selfadjointView<Lower>() * (eiSymmGen.eigenvectors() * eiSymmGen.eigenvalues().asDiagonal()), largerEps)); MatrixType sqrtSymmA = eiSymm.operatorSqrt(); - VERIFY_IS_APPROX(symmA, sqrtSymmA*sqrtSymmA); - VERIFY_IS_APPROX(sqrtSymmA, symmA*eiSymm.operatorInverseSqrt()); + VERIFY_IS_APPROX(MatrixType(symmA.template selfadjointView<Lower>()), sqrtSymmA*sqrtSymmA); + VERIFY_IS_APPROX(sqrtSymmA, symmA.template selfadjointView<Lower>()*eiSymm.operatorInverseSqrt()); MatrixType id = MatrixType::Identity(rows, cols); VERIFY_IS_APPROX(id.template selfadjointView<Lower>().operatorNorm(), RealScalar(1)); + + SelfAdjointEigenSolver<MatrixType> eiSymmUninitialized; + VERIFY_RAISES_ASSERT(eiSymmUninitialized.info()); + VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvalues()); + VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvectors()); + VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorSqrt()); + VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorInverseSqrt()); + + eiSymmUninitialized.compute(symmA, false); + VERIFY_RAISES_ASSERT(eiSymmUninitialized.eigenvectors()); + VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorSqrt()); + VERIFY_RAISES_ASSERT(eiSymmUninitialized.operatorInverseSqrt()); + + if (rows > 1) + { + // Test matrix with NaN + symmA(0,0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN(); + SelfAdjointEigenSolver<MatrixType> eiSymmNaN(symmA); + VERIFY_IS_EQUAL(eiSymmNaN.info(), NoConvergence); + } } void test_eigensolver_selfadjoint() diff --git a/test/first_aligned.cpp b/test/first_aligned.cpp index f00ed57a5..687f4a5dc 100644 --- a/test/first_aligned.cpp +++ b/test/first_aligned.cpp @@ -34,6 +34,8 @@ void test_first_aligned_helper(Scalar *array, int size) template<typename Scalar> void test_none_aligned_helper(Scalar *array, int size) { + EIGEN_UNUSED_VARIABLE(array); + EIGEN_UNUSED_VARIABLE(size); VERIFY(ei_packet_traits<Scalar>::size == 1 || ei_first_aligned(array, size) == size); } diff --git a/test/hessenberg.cpp b/test/hessenberg.cpp index 16aa564ae..b4cfe288d 100644 --- a/test/hessenberg.cpp +++ b/test/hessenberg.cpp @@ -54,6 +54,13 @@ template<typename Scalar,int Size> void hessenberg(int size = Size) MatrixType cs2Q = cs2.matrixQ(); VERIFY_IS_EQUAL(cs1Q, cs2Q); + // Test assertions for when used uninitialized + HessenbergDecomposition<MatrixType> hessUninitialized; + VERIFY_RAISES_ASSERT( hessUninitialized.matrixH() ); + VERIFY_RAISES_ASSERT( hessUninitialized.matrixQ() ); + VERIFY_RAISES_ASSERT( hessUninitialized.householderCoefficients() ); + VERIFY_RAISES_ASSERT( hessUninitialized.packedMatrix() ); + // TODO: Add tests for packedMatrix() and householderCoefficients() } diff --git a/test/integer_types.cpp b/test/integer_types.cpp index 4e7a093c6..d2feb8a65 100644 --- a/test/integer_types.cpp +++ b/test/integer_types.cpp @@ -31,7 +31,37 @@ #undef VERIFY_IS_NOT_APPROX #define VERIFY_IS_NOT_APPROX(a, b) VERIFY((a)!=(b)); -template<typename MatrixType> void integer_types(const MatrixType& m) +template<typename MatrixType> void signed_integer_type_tests(const MatrixType& m) +{ + typedef typename MatrixType::Scalar Scalar; + + enum { is_signed = (Scalar(-1) > Scalar(0)) ? 0 : 1 }; + VERIFY(is_signed == 1); + + int rows = m.rows(); + int cols = m.cols(); + + MatrixType m1(rows, cols), + m2 = MatrixType::Random(rows, cols), + mzero = MatrixType::Zero(rows, cols); + + do { + m1 = MatrixType::Random(rows, cols); + } while(m1 == mzero || m1 == m2); + + // check linear structure + + Scalar s1; + do { + s1 = ei_random<Scalar>(); + } while(s1 == 0); + + VERIFY_IS_EQUAL(-(-m1), m1); + VERIFY_IS_EQUAL(-m2+m1+m2, m1); + VERIFY_IS_EQUAL((-m1+m2)*s1, -s1*m1+s1*m2); +} + +template<typename MatrixType> void integer_type_tests(const MatrixType& m) { typedef typename MatrixType::Scalar Scalar; @@ -97,13 +127,10 @@ template<typename MatrixType> void integer_types(const MatrixType& m) s1 = ei_random<Scalar>(); } while(s1 == 0); - VERIFY_IS_EQUAL(-(-m1), m1); VERIFY_IS_EQUAL(m1+m1, 2*m1); VERIFY_IS_EQUAL(m1+m2-m1, m2); - VERIFY_IS_EQUAL(-m2+m1+m2, m1); VERIFY_IS_EQUAL(m1*s1, s1*m1); VERIFY_IS_EQUAL((m1+m2)*s1, s1*m1+s1*m2); - VERIFY_IS_EQUAL((-m1+m2)*s1, -s1*m1+s1*m2); m3 = m2; m3 += m1; VERIFY_IS_EQUAL(m3, m1+m2); m3 = m2; m3 -= m1; @@ -122,18 +149,26 @@ template<typename MatrixType> void integer_types(const MatrixType& m) void test_integer_types() { for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST_1( integer_types(Matrix<unsigned int, 1, 1>()) ); - CALL_SUBTEST_1( integer_types(Matrix<unsigned long, 3, 4>()) ); - CALL_SUBTEST_2( integer_types(Matrix<long, 2, 2>()) ); + CALL_SUBTEST_1( integer_type_tests(Matrix<unsigned int, 1, 1>()) ); + CALL_SUBTEST_1( integer_type_tests(Matrix<unsigned long, 3, 4>()) ); + + CALL_SUBTEST_2( integer_type_tests(Matrix<long, 2, 2>()) ); + CALL_SUBTEST_2( signed_integer_type_tests(Matrix<long, 2, 2>()) ); + + CALL_SUBTEST_3( integer_type_tests(Matrix<char, 2, Dynamic>(2, 10)) ); + CALL_SUBTEST_3( signed_integer_type_tests(Matrix<char, 2, Dynamic>(2, 10)) ); + + CALL_SUBTEST_4( integer_type_tests(Matrix<unsigned char, 3, 3>()) ); + CALL_SUBTEST_4( integer_type_tests(Matrix<unsigned char, Dynamic, Dynamic>(20, 20)) ); + + CALL_SUBTEST_5( integer_type_tests(Matrix<short, Dynamic, 4>(7, 4)) ); + CALL_SUBTEST_5( signed_integer_type_tests(Matrix<short, Dynamic, 4>(7, 4)) ); - CALL_SUBTEST_3( integer_types(Matrix<char, 2, Dynamic>(2, 10)) ); - CALL_SUBTEST_4( integer_types(Matrix<unsigned char, 3, 3>()) ); - CALL_SUBTEST_4( integer_types(Matrix<unsigned char, Dynamic, Dynamic>(20, 20)) ); + CALL_SUBTEST_6( integer_type_tests(Matrix<unsigned short, 4, 4>()) ); - CALL_SUBTEST_5( integer_types(Matrix<short, Dynamic, 4>(7, 4)) ); - CALL_SUBTEST_6( integer_types(Matrix<unsigned short, 4, 4>()) ); + CALL_SUBTEST_7( integer_type_tests(Matrix<long long, 11, 13>()) ); + CALL_SUBTEST_7( signed_integer_type_tests(Matrix<long long, 11, 13>()) ); - CALL_SUBTEST_7( integer_types(Matrix<long long, 11, 13>()) ); - CALL_SUBTEST_8( integer_types(Matrix<unsigned long long, Dynamic, 5>(1, 5)) ); + CALL_SUBTEST_8( integer_type_tests(Matrix<unsigned long long, Dynamic, 5>(1, 5)) ); } } diff --git a/test/inverse.cpp b/test/inverse.cpp index 1e567ad14..108ce7bcb 100644 --- a/test/inverse.cpp +++ b/test/inverse.cpp @@ -78,10 +78,23 @@ template<typename MatrixType> void inverse(const MatrixType& m) MatrixType m3 = v3*v3.transpose(), m4(rows,cols); m3.computeInverseAndDetWithCheck(m4, det, invertible); VERIFY( rows==1 ? invertible : !invertible ); - VERIFY_IS_APPROX(det, m3.determinant()); + VERIFY_IS_MUCH_SMALLER_THAN(ei_abs(det-m3.determinant()), RealScalar(1)); m3.computeInverseWithCheck(m4, invertible); VERIFY( rows==1 ? invertible : !invertible ); #endif + + // check in-place inversion + if(MatrixType::RowsAtCompileTime>=2 && MatrixType::RowsAtCompileTime<=4) + { + // in-place is forbidden + VERIFY_RAISES_ASSERT(m1 = m1.inverse()); + } + else + { + m2 = m1.inverse(); + m1 = m1.inverse(); + VERIFY_IS_APPROX(m1,m2); + } } void test_inverse() diff --git a/test/lu.cpp b/test/lu.cpp index 22dca76d2..9aa793e00 100644 --- a/test/lu.cpp +++ b/test/lu.cpp @@ -120,7 +120,7 @@ template<typename MatrixType> void lu_invertible() MatrixType m1(size, size), m2(size, size), m3(size, size); FullPivLU<MatrixType> lu; - lu.setThreshold(0.01); + lu.setThreshold(RealScalar(0.01)); do { m1 = MatrixType::Random(size,size); lu.compute(m1); diff --git a/test/main.h b/test/main.h index d1a68befb..184a35b15 100644 --- a/test/main.h +++ b/test/main.h @@ -368,7 +368,7 @@ inline bool test_isUnitary(const MatrixBase<Derived>& m) } template<typename T, typename U> -bool test_is_equal(T actual, U expected) +bool test_is_equal(const T& actual, const U& expected) { if (actual==expected) return true; diff --git a/test/nullary.cpp b/test/nullary.cpp index 3adfc33fe..6e91ddd52 100644 --- a/test/nullary.cpp +++ b/test/nullary.cpp @@ -51,8 +51,8 @@ void testVectorType(const VectorType& base) { typedef typename ei_traits<VectorType>::Scalar Scalar; Scalar low = ei_random<Scalar>(-500,500); - Scalar high = ei_random<Scalar>(-500,500); - if (low>high) std::swap(low,high); + Scalar high = ei_random<Scalar>(-500,500); + if (low>high) std::swap(low,high); const int size = base.size(); const Scalar step = (high-low)/(size-1); @@ -91,7 +91,7 @@ void testVectorType(const VectorType& base) Matrix<Scalar,Dynamic,1> size_changer(size+50); size_changer.setLinSpaced(low,high,size); - VERIFY( size_changer.size() == size ); + VERIFY( size_changer.size() == size ); } template<typename MatrixType> diff --git a/test/prec_inverse_4x4.cpp b/test/prec_inverse_4x4.cpp index 05dbee7b5..4150caec2 100644 --- a/test/prec_inverse_4x4.cpp +++ b/test/prec_inverse_4x4.cpp @@ -64,9 +64,7 @@ template<typename MatrixType> void inverse_general_4x4(int repeat) double error_avg = error_sum / repeat; EIGEN_DEBUG_VAR(error_avg); EIGEN_DEBUG_VAR(error_max); - // FIXME that 1.3 used to be a 1.0 until the NumTraits changes on 28 April 2010, and then a 1.2 until the ReturnByValue/Inverse changes - // on 30 May 2010, what's going wrong (if anything) ?? - VERIFY(error_avg < (NumTraits<Scalar>::IsComplex ? 8.0 : 1.3)); + VERIFY(error_avg < (NumTraits<Scalar>::IsComplex ? 8.0 : 1.2)); // FIXME that 1.2 used to be a 1.0 until the NumTraits changes on 28 April 2010, what's going wrong?? VERIFY(error_max < (NumTraits<Scalar>::IsComplex ? 64.0 : 20.0)); } diff --git a/test/product.h b/test/product.h index 277b73c45..71dc4bde2 100644 --- a/test/product.h +++ b/test/product.h @@ -71,8 +71,9 @@ template<typename MatrixType> void product(const MatrixType& m) Scalar s1 = ei_random<Scalar>(); - int r = ei_random<int>(0, rows-1), - c = ei_random<int>(0, cols-1); + int r = ei_random<int>(0, rows-1), + c = ei_random<int>(0, cols-1), + c2 = ei_random<int>(0, cols-1); // begin testing Product.h: only associativity for now // (we use Transpose.h but this doesn't count as a test for it) @@ -150,4 +151,8 @@ template<typename MatrixType> void product(const MatrixType& m) { VERIFY(areNotApprox(res2,square2 + m2.transpose() * m1)); } + + // inner product + Scalar x = square2.row(c) * square2.col(c2); + VERIFY_IS_APPROX(x, square2.row(c).transpose().cwiseProduct(square2.col(c2)).sum()); } diff --git a/test/product_large.cpp b/test/product_large.cpp index 519213236..0351d134c 100644 --- a/test/product_large.cpp +++ b/test/product_large.cpp @@ -49,5 +49,22 @@ void test_product_large() MatrixXf a = MatrixXf::Random(10,4), b = MatrixXf::Random(4,10), c = a; VERIFY_IS_APPROX((a = a * b), (c * b).eval()); } + + { + // check the functions to setup blocking sizes compile and do not segfault + // FIXME check they do what they are supposed to do !! + std::ptrdiff_t l1 = ei_random<int>(10000,20000); + std::ptrdiff_t l2 = ei_random<int>(1000000,2000000); + setCpuCacheSizes(l1,l2); + VERIFY(l1==l1CacheSize()); + VERIFY(l2==l2CacheSize()); + std::ptrdiff_t k1 = ei_random<int>(10,100)*16; + std::ptrdiff_t m1 = ei_random<int>(10,100)*16; + std::ptrdiff_t n1 = ei_random<int>(10,100)*16; + setBlockingSizes<float>(k1,m1,n1); + std::ptrdiff_t k, m, n; + getBlockingSizes<float>(k,m,n); + VERIFY(k==k1 && m==m1 && n==n1); + } #endif } diff --git a/test/schur_complex.cpp b/test/schur_complex.cpp index b33411cf2..7c4dcb21a 100644 --- a/test/schur_complex.cpp +++ b/test/schur_complex.cpp @@ -23,6 +23,7 @@ // Eigen. If not, see <http://www.gnu.org/licenses/>. #include "main.h" +#include <limits> #include <Eigen/Eigenvalues> template<typename MatrixType> void schur(int size = MatrixType::ColsAtCompileTime) @@ -34,6 +35,7 @@ template<typename MatrixType> void schur(int size = MatrixType::ColsAtCompileTim for(int counter = 0; counter < g_repeat; ++counter) { MatrixType A = MatrixType::Random(size, size); ComplexSchur<MatrixType> schurOfA(A); + VERIFY_IS_EQUAL(schurOfA.info(), Success); ComplexMatrixType U = schurOfA.matrixU(); ComplexMatrixType T = schurOfA.matrixT(); for(int row = 1; row < size; ++row) { @@ -48,14 +50,31 @@ template<typename MatrixType> void schur(int size = MatrixType::ColsAtCompileTim ComplexSchur<MatrixType> csUninitialized; VERIFY_RAISES_ASSERT(csUninitialized.matrixT()); VERIFY_RAISES_ASSERT(csUninitialized.matrixU()); + VERIFY_RAISES_ASSERT(csUninitialized.info()); // Test whether compute() and constructor returns same result MatrixType A = MatrixType::Random(size, size); ComplexSchur<MatrixType> cs1; cs1.compute(A); ComplexSchur<MatrixType> cs2(A); + VERIFY_IS_EQUAL(cs1.info(), Success); + VERIFY_IS_EQUAL(cs2.info(), Success); VERIFY_IS_EQUAL(cs1.matrixT(), cs2.matrixT()); VERIFY_IS_EQUAL(cs1.matrixU(), cs2.matrixU()); + + // Test computation of only T, not U + ComplexSchur<MatrixType> csOnlyT(A, false); + VERIFY_IS_EQUAL(csOnlyT.info(), Success); + VERIFY_IS_EQUAL(cs1.matrixT(), csOnlyT.matrixT()); + VERIFY_RAISES_ASSERT(csOnlyT.matrixU()); + + if (size > 1) + { + // Test matrix with NaN + A(0,0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN(); + ComplexSchur<MatrixType> csNaN(A); + VERIFY_IS_EQUAL(csNaN.info(), NoConvergence); + } } void test_schur_complex() diff --git a/test/schur_real.cpp b/test/schur_real.cpp index bcb19c936..2eae52956 100644 --- a/test/schur_real.cpp +++ b/test/schur_real.cpp @@ -23,6 +23,7 @@ // Eigen. If not, see <http://www.gnu.org/licenses/>. #include "main.h" +#include <limits> #include <Eigen/Eigenvalues> template<typename MatrixType> void verifyIsQuasiTriangular(const MatrixType& T) @@ -55,6 +56,7 @@ template<typename MatrixType> void schur(int size = MatrixType::ColsAtCompileTim for(int counter = 0; counter < g_repeat; ++counter) { MatrixType A = MatrixType::Random(size, size); RealSchur<MatrixType> schurOfA(A); + VERIFY_IS_EQUAL(schurOfA.info(), Success); MatrixType U = schurOfA.matrixU(); MatrixType T = schurOfA.matrixT(); verifyIsQuasiTriangular(T); @@ -65,14 +67,31 @@ template<typename MatrixType> void schur(int size = MatrixType::ColsAtCompileTim RealSchur<MatrixType> rsUninitialized; VERIFY_RAISES_ASSERT(rsUninitialized.matrixT()); VERIFY_RAISES_ASSERT(rsUninitialized.matrixU()); + VERIFY_RAISES_ASSERT(rsUninitialized.info()); // Test whether compute() and constructor returns same result MatrixType A = MatrixType::Random(size, size); RealSchur<MatrixType> rs1; rs1.compute(A); RealSchur<MatrixType> rs2(A); + VERIFY_IS_EQUAL(rs1.info(), Success); + VERIFY_IS_EQUAL(rs2.info(), Success); VERIFY_IS_EQUAL(rs1.matrixT(), rs2.matrixT()); VERIFY_IS_EQUAL(rs1.matrixU(), rs2.matrixU()); + + // Test computation of only T, not U + RealSchur<MatrixType> rsOnlyT(A, false); + VERIFY_IS_EQUAL(rsOnlyT.info(), Success); + VERIFY_IS_EQUAL(rs1.matrixT(), rsOnlyT.matrixT()); + VERIFY_RAISES_ASSERT(rsOnlyT.matrixU()); + + if (size > 1) + { + // Test matrix with NaN + A(0,0) = std::numeric_limits<typename MatrixType::Scalar>::quiet_NaN(); + RealSchur<MatrixType> rsNaN(A); + VERIFY_IS_EQUAL(rsNaN.info(), NoConvergence); + } } void test_schur_real() diff --git a/test/selfadjoint.cpp b/test/selfadjoint.cpp index 2eaf6d459..1ea5a3a3c 100644 --- a/test/selfadjoint.cpp +++ b/test/selfadjoint.cpp @@ -55,7 +55,7 @@ void test_selfadjoint() { for(int i = 0; i < g_repeat ; i++) { - EIGEN_UNUSED int s = ei_random<int>(1,20); + int s = ei_random<int>(1,20); EIGEN_UNUSED_VARIABLE(s); CALL_SUBTEST_1( selfadjoint(Matrix<float, 1, 1>()) ); CALL_SUBTEST_2( selfadjoint(Matrix<float, 2, 2>()) ); diff --git a/test/sparse.h b/test/sparse.h index f0d230153..4733e4d10 100644 --- a/test/sparse.h +++ b/test/sparse.h @@ -81,13 +81,13 @@ initSparse(double density, v = Scalar(0); else if ((flags & MakeUpperTriangular) && j<i) v = Scalar(0); - + if ((flags&ForceRealDiag) && (i==j)) v = ei_real(v); - + if (v!=Scalar(0)) { - sparseMat.insertBack(j,i) = v; + sparseMat.insertBackByOuterInner(j,i) = v; if (nonzeroCoords) nonzeroCoords->push_back(Vector2i(i,j)); } @@ -126,13 +126,13 @@ initSparse(double density, v = Scalar(0); else if ((flags & MakeUpperTriangular) && j<i) v = Scalar(0); - + if ((flags&ForceRealDiag) && (i==j)) v = ei_real(v); - + if (v!=Scalar(0)) { - sparseMat.insertBack(j,i) = v; + sparseMat.insertBackByOuterInner(j,i) = v; if (nonzeroCoords) nonzeroCoords->push_back(Vector2i(i,j)); } diff --git a/test/sparse_basic.cpp b/test/sparse_basic.cpp index 9de156d38..43d9c6254 100644 --- a/test/sparse_basic.cpp +++ b/test/sparse_basic.cpp @@ -323,12 +323,12 @@ template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& re else if (x<0.5) { countFalseNonZero++; - m2.insertBack(j,i) = Scalar(0); + m2.insertBackByOuterInner(j,i) = Scalar(0); } else { countTrueNonZero++; - m2.insertBack(j,i) = refM2(i,j) = Scalar(1); + m2.insertBackByOuterInner(j,i) = refM2(i,j) = Scalar(1); } } } diff --git a/test/sparse_solvers.cpp b/test/sparse_solvers.cpp index 00df1bffd..ea8aee718 100644 --- a/test/sparse_solvers.cpp +++ b/test/sparse_solvers.cpp @@ -149,26 +149,27 @@ template<typename Scalar> void sparse_solvers(int rows, int cols) } // test LDLT - if (!NumTraits<Scalar>::IsComplex) { - // TODO fix the issue with complex (see SparseLDLT::solveInPlace) SparseMatrix<Scalar> m2(rows, cols); DenseMatrix refMat2(rows, cols); DenseVector b = DenseVector::Random(cols); DenseVector refX(cols), x(cols); -// initSPD(density, refMat2, m2); initSparse<Scalar>(density, refMat2, m2, ForceNonZeroDiag|MakeUpperTriangular, 0, 0); - refMat2 += (refMat2.adjoint()).eval(); - refMat2.diagonal() *= 0.5; + for(int i=0; i<rows; ++i) + m2.coeffRef(i,i) = refMat2(i,i) = ei_abs(ei_real(refMat2(i,i))); - refX = refMat2.llt().solve(b); // FIXME use LLT to compute the reference because LDLT seems to fail with large matrices + refX = refMat2.template selfadjointView<Upper>().llt().solve(b); + // FIXME use LLT to compute the reference because LDLT seems to fail with large matrices typedef SparseMatrix<Scalar,Upper|SelfAdjoint> SparseSelfAdjointMatrix; x = b; SparseLDLT<SparseSelfAdjointMatrix> ldlt(m2); if (ldlt.succeeded()) ldlt.solveInPlace(x); + else + std::cerr << "warning LDLT failed\n"; + VERIFY(refX.isApprox(x,test_precision<Scalar>()) && "LDLT: default"); } diff --git a/test/stable_norm.cpp b/test/stable_norm.cpp index b0c6e0183..77b062303 100644 --- a/test/stable_norm.cpp +++ b/test/stable_norm.cpp @@ -24,6 +24,11 @@ #include "main.h" +template<typename T> bool isFinite(const T& x) +{ + return x==x && x>=NumTraits<T>::lowest() && x<=NumTraits<T>::highest(); +} + template<typename MatrixType> void stable_norm(const MatrixType& m) { /* this test covers the following files: @@ -50,7 +55,7 @@ template<typename MatrixType> void stable_norm(const MatrixType& m) int rows = m.rows(); int cols = m.cols(); - Scalar big = ei_abs(ei_random<Scalar>()) * (std::numeric_limits<RealScalar>::max() * RealScalar(1e-4)); + Scalar big = ei_random<Scalar>() * (std::numeric_limits<RealScalar>::max() * RealScalar(1e-4)); Scalar small = static_cast<RealScalar>(1)/big; MatrixType vzero = MatrixType::Zero(rows, cols), @@ -68,22 +73,35 @@ template<typename MatrixType> void stable_norm(const MatrixType& m) RealScalar size = static_cast<RealScalar>(m.size()); - // test overflow -/* VERIFY_IS_NOT_APPROX(static_cast<Scalar>(vbig.norm()), ei_sqrt(size)*big); // here the default norm must fail - Does not succeed on gcc (Ubuntu 4.4.1-4ubuntu9) 4.4.1, Intel Core 2 Duo T7300 with no SSE optimizations -*/ + // test isFinite + VERIFY(!isFinite( std::numeric_limits<RealScalar>::infinity())); + VERIFY(!isFinite(ei_sqrt(-ei_abs(big)))); - VERIFY_IS_APPROX(static_cast<Scalar>(vbig.stableNorm()), ei_sqrt(size)*big); - VERIFY_IS_APPROX(static_cast<Scalar>(vbig.blueNorm()), ei_sqrt(size)*big); - VERIFY_IS_APPROX(static_cast<Scalar>(vbig.hypotNorm()), ei_sqrt(size)*big); + // test overflow + VERIFY(isFinite(ei_sqrt(size)*ei_abs(big))); + #ifdef EIGEN_VECTORIZE_SSE + // since x87 FPU uses 80bits of precision overflow is not detected + if(ei_packet_traits<Scalar>::size>1) + { + VERIFY_IS_NOT_APPROX(static_cast<Scalar>(vbig.norm()), ei_sqrt(size)*big); // here the default norm must fail + } + #endif + VERIFY_IS_APPROX(vbig.stableNorm(), ei_sqrt(size)*ei_abs(big)); + VERIFY_IS_APPROX(vbig.blueNorm(), ei_sqrt(size)*ei_abs(big)); + VERIFY_IS_APPROX(vbig.hypotNorm(), ei_sqrt(size)*ei_abs(big)); // test underflow -/* VERIFY_IS_NOT_APPROX(static_cast<Scalar>(vsmall.norm()), ei_sqrt(size)*small); // here the default norm must fail - Does not succeed on gcc (Ubuntu 4.4.1-4ubuntu9) 4.4.1, Intel Core 2 Duo T7300 with no SSE optimizations -*/ - VERIFY_IS_APPROX(static_cast<Scalar>(vsmall.stableNorm()), ei_sqrt(size)*small); - VERIFY_IS_APPROX(static_cast<Scalar>(vsmall.blueNorm()), ei_sqrt(size)*small); - VERIFY_IS_APPROX(static_cast<Scalar>(vsmall.hypotNorm()), ei_sqrt(size)*small); + VERIFY(isFinite(ei_sqrt(size)*ei_abs(small))); + #ifdef EIGEN_VECTORIZE_SSE + // since x87 FPU uses 80bits of precision underflow is not detected + if(ei_packet_traits<Scalar>::size>1) + { + VERIFY_IS_NOT_APPROX(static_cast<Scalar>(vsmall.norm()), ei_sqrt(size)*small); // here the default norm must fail + } + #endif + VERIFY_IS_APPROX(vsmall.stableNorm(), ei_sqrt(size)*ei_abs(small)); + VERIFY_IS_APPROX(vsmall.blueNorm(), ei_sqrt(size)*ei_abs(small)); + VERIFY_IS_APPROX(vsmall.hypotNorm(), ei_sqrt(size)*ei_abs(small)); // Test compilation of cwise() version VERIFY_IS_APPROX(vrand.colwise().stableNorm(), vrand.colwise().norm()); diff --git a/test/stdlist.cpp b/test/stdlist.cpp index 451c7752d..c612e634a 100644 --- a/test/stdlist.cpp +++ b/test/stdlist.cpp @@ -48,8 +48,13 @@ void check_stdlist_matrix(const MatrixType& m) ++wi; } - v.resize(21); + v.resize(21); v.back() = x; + if (!test_ei_isApprox(v.back(),x)) + { + std::cout << x << std::endl; + std::cout << v.back() << std::endl; + } VERIFY_IS_APPROX(v.back(), x); v.resize(22,y); VERIFY_IS_APPROX(v.back(), y); @@ -112,6 +117,11 @@ void check_stdlist_quaternion(const QuaternionType&) v.resize(22,y); VERIFY_IS_APPROX(v.back(), y); v.push_back(x); + if (!test_ei_isApprox(v.back(),x)) + { + std::cout << x << std::endl; + std::cout << v.back() << std::endl; + } VERIFY_IS_APPROX(v.back(), x); } diff --git a/test/triangular.cpp b/test/triangular.cpp index d6d64e595..12452515e 100644 --- a/test/triangular.cpp +++ b/test/triangular.cpp @@ -235,8 +235,8 @@ void test_triangular() { for(int i = 0; i < g_repeat ; i++) { - EIGEN_UNUSED int r = ei_random<int>(2,20); - EIGEN_UNUSED int c = ei_random<int>(2,20); + int r = ei_random<int>(2,20); EIGEN_UNUSED_VARIABLE(r); + int c = ei_random<int>(2,20); EIGEN_UNUSED_VARIABLE(c); CALL_SUBTEST_1( triangular_square(Matrix<float, 1, 1>()) ); CALL_SUBTEST_2( triangular_square(Matrix<float, 2, 2>()) ); diff --git a/test/unalignedcount.cpp b/test/unalignedcount.cpp index feff870e5..74eab8c6a 100644 --- a/test/unalignedcount.cpp +++ b/test/unalignedcount.cpp @@ -52,5 +52,8 @@ void test_unalignedcount() VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) -= b.segment(0,40), 10, 10, 10, 0); VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) *= 3.5, 10, 0, 10, 0); VERIFY_ALIGNED_UNALIGNED_COUNT(a.segment(0,40) /= 3.5, 10, 0, 10, 0); + #else + // The following line is to eliminate "variable not used" warnings + nb_load = nb_loadu = nb_store = nb_storeu = 0; #endif } diff --git a/unsupported/Eigen/FFT b/unsupported/Eigen/FFT index a41a89a8a..0e8e57e50 100644 --- a/unsupported/Eigen/FFT +++ b/unsupported/Eigen/FFT @@ -136,10 +136,12 @@ struct fft_fwd_proxy int rows() const { return m_src.rows(); } int cols() const { return m_src.cols(); } - protected: - const T_SrcMat & m_src; - T_FftIfc & m_ifc; - int m_nfft; +protected: + const T_SrcMat & m_src; + T_FftIfc & m_ifc; + int m_nfft; +private: + fft_fwd_proxy& operator=(const fft_fwd_proxy&); }; template<typename T_SrcMat,typename T_FftIfc> @@ -152,10 +154,12 @@ struct fft_inv_proxy int rows() const { return m_src.rows(); } int cols() const { return m_src.cols(); } - protected: - const T_SrcMat & m_src; - T_FftIfc & m_ifc; - int m_nfft; +protected: + const T_SrcMat & m_src; + T_FftIfc & m_ifc; + int m_nfft; +private: + fft_inv_proxy& operator=(const fft_inv_proxy&); }; diff --git a/unsupported/Eigen/src/BVH/BVAlgorithms.h b/unsupported/Eigen/src/BVH/BVAlgorithms.h index 63725763a..40320291d 100644 --- a/unsupported/Eigen/src/BVH/BVAlgorithms.h +++ b/unsupported/Eigen/src/BVH/BVAlgorithms.h @@ -86,9 +86,11 @@ struct ei_intersector_helper2 bool intersectObject(const Object2 &obj) { return intersector.intersectObjectObject(stored, obj); } Object1 stored; Intersector &intersector; +private: + ei_intersector_helper2& operator=(const ei_intersector_helper2&); }; -/** Given two BVH's, runs the query on their cartesian product encapsulated by \a intersector. +/** Given two BVH's, runs the query on their Cartesian product encapsulated by \a intersector. * The Intersector type must provide the following members: \code bool intersectVolumeVolume(const BVH1::Volume &v1, const BVH2::Volume &v2) //returns true if product of volumes intersects the query bool intersectVolumeObject(const BVH1::Volume &v1, const BVH2::Object &o2) //returns true if the volume-object product intersects the query @@ -207,6 +209,8 @@ struct ei_minimizer_helper1 Scalar minimumOnObject(const Object1 &obj) { return minimizer.minimumOnObjectObject(obj, stored); } Object2 stored; Minimizer &minimizer; +private: + ei_minimizer_helper1& operator=(const ei_minimizer_helper1&) {} }; template<typename Volume2, typename Object2, typename Object1, typename Minimizer> diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h index 5d47f2cec..a4d827746 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixExponential.h @@ -323,6 +323,8 @@ template<typename Derived> struct MatrixExponentialReturnValue protected: const Derived& m_src; + private: + MatrixExponentialReturnValue& operator=(const MatrixExponentialReturnValue&); }; template<typename Derived> diff --git a/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h b/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h index be27c5037..c16341b17 100644 --- a/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h +++ b/unsupported/Eigen/src/MatrixFunctions/MatrixFunction.h @@ -116,9 +116,10 @@ class MatrixFunction<MatrixType, 0> } private: - const MatrixType& m_A; /**< \brief Reference to argument of matrix function. */ StemFunction *m_f; /**< \brief Stem function for matrix function under consideration */ + + MatrixFunction& operator=(const MatrixFunction&); }; @@ -182,6 +183,8 @@ class MatrixFunction<MatrixType, 1> * separation constant is set to 0.1, a value taken from the * paper by Davies and Higham. */ static const RealScalar separation() { return static_cast<RealScalar>(0.1); } + + MatrixFunction& operator=(const MatrixFunction&); }; /** \brief Constructor. @@ -526,6 +529,8 @@ template<typename Derived> class MatrixFunctionReturnValue private: const Derived& m_A; StemFunction *m_f; + + MatrixFunctionReturnValue& operator=(const MatrixFunctionReturnValue&); }; template<typename Derived> diff --git a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h index aba31b238..0ef3ecafa 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h +++ b/unsupported/Eigen/src/NonLinearOptimization/HybridNonLinearSolver.h @@ -124,6 +124,8 @@ private: Index ncfail; Scalar actred, prered; FVectorType wa1, wa2, wa3, wa4; + + HybridNonLinearSolver& operator=(const HybridNonLinearSolver&); }; diff --git a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h index 63eb66738..a8f3f3e64 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h +++ b/unsupported/Eigen/src/NonLinearOptimization/LevenbergMarquardt.h @@ -133,6 +133,8 @@ private: Scalar delta; Scalar ratio; Scalar pnorm, xnorm, fnorm1, actred, dirder, prered; + + LevenbergMarquardt& operator=(const LevenbergMarquardt&); }; template<typename FunctorType, typename Scalar> diff --git a/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h b/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h index bce8a4441..15a27d53d 100644 --- a/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h +++ b/unsupported/Eigen/src/NonLinearOptimization/qrsolv.h @@ -70,7 +70,7 @@ void ei_qrsolv( /* solve the triangular system for z. if the system is */ /* singular, then obtain a least squares solution. */ Index nsing; - for (nsing=0; nsing<n && sdiag[nsing]!=0; nsing++); + for(nsing=0; nsing<n && sdiag[nsing]!=0; nsing++) {} wa.tail(n-nsing).setZero(); s.topLeftCorner(nsing, nsing).transpose().template triangularView<Upper>().solveInPlace(wa.head(nsing)); diff --git a/unsupported/Eigen/src/NumericalDiff/NumericalDiff.h b/unsupported/Eigen/src/NumericalDiff/NumericalDiff.h index 8d23cb4ae..a25c9cd6d 100644 --- a/unsupported/Eigen/src/NumericalDiff/NumericalDiff.h +++ b/unsupported/Eigen/src/NumericalDiff/NumericalDiff.h @@ -130,6 +130,8 @@ public: } private: Scalar epsfcn; + + NumericalDiff& operator=(const NumericalDiff&); }; //vim: ai ts=4 sts=4 et sw=4 diff --git a/unsupported/test/NonLinearOptimization.cpp b/unsupported/test/NonLinearOptimization.cpp index 3257d0597..cb70f2a74 100644 --- a/unsupported/test/NonLinearOptimization.cpp +++ b/unsupported/test/NonLinearOptimization.cpp @@ -8,6 +8,10 @@ #include "main.h" #include <unsupported/Eigen/NonLinearOptimization> +// This disables some useless Warnings on MSVC. +// It is intended to be done for this test only. +#include <Eigen/src/Core/util/DisableMSVCWarnings.h> + int fcn_chkder(const VectorXd &x, VectorXd &fvec, MatrixXd &fjac, int iflag) { /* subroutine fcn for chkder example. */ |