diff options
author | Gael Guennebaud <g.gael@free.fr> | 2011-01-26 16:33:23 +0100 |
---|---|---|
committer | Gael Guennebaud <g.gael@free.fr> | 2011-01-26 16:33:23 +0100 |
commit | 15ef62ca43c2e08c1e2fefb751b994441e019376 (patch) | |
tree | 85b8e86cedb33e44f259275a814ec983d802b855 | |
parent | 84448b058c1611a0eae45212007d02a0c5457f5c (diff) |
extend PermutationMatrix and Transpositions to support arbitrary interger types and to support the Map/Wrapper model via base and derived classes
-rw-r--r-- | Eigen/src/Core/MatrixBase.h | 1 | ||||
-rw-r--r-- | Eigen/src/Core/PermutationMatrix.h | 495 | ||||
-rw-r--r-- | Eigen/src/Core/Transpositions.h | 295 | ||||
-rw-r--r-- | Eigen/src/Core/util/ForwardDeclarations.h | 8 | ||||
-rw-r--r-- | Eigen/src/LU/PartialPivLU.h | 8 | ||||
-rw-r--r-- | test/permutationmatrices.cpp | 11 |
6 files changed, 601 insertions, 217 deletions
diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 0a444bd02..40e44c9b3 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -277,6 +277,7 @@ template<typename Derived> class MatrixBase static const BasisReturnType UnitW(); const DiagonalWrapper<const Derived> asDiagonal() const; + const PermutationWrapper<const Derived> asPermutation() const; Derived& setIdentity(); Derived& setIdentity(Index rows, Index cols); diff --git a/Eigen/src/Core/PermutationMatrix.h b/Eigen/src/Core/PermutationMatrix.h index f53dd8772..06787a66d 100644 --- a/Eigen/src/Core/PermutationMatrix.h +++ b/Eigen/src/Core/PermutationMatrix.h @@ -2,7 +2,7 @@ // for linear algebra. // // Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com> -// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr> +// Copyright (C) 2009-2011 Gael Guennebaud <gael.guennebaud@inria.fr> // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -26,15 +26,17 @@ #ifndef EIGEN_PERMUTATIONMATRIX_H #define EIGEN_PERMUTATIONMATRIX_H -/** \class PermutationMatrix +template<int RowCol,typename IndicesType,typename MatrixType, typename StorageKind> class PermutedImpl; + +/** \class PermutationBase * \ingroup Core_Module * - * \brief Permutation matrix + * \brief Base class for permutations * - * \param SizeAtCompileTime the number of rows/cols, or Dynamic - * \param MaxSizeAtCompileTime the maximum number of rows/cols, or Dynamic. This optional parameter defaults to SizeAtCompileTime. Most of the time, you should not have to specify it. + * \param Derived the derived class * - * This class represents a permutation matrix, internally stored as a vector of integers. + * This class is the base class for all expressions representing a permutation matrix, + * internally stored as a vector of integers. * The convention followed here is that if \f$ \sigma \f$ is a permutation, the corresponding permutation matrix * \f$ P_\sigma \f$ is such that if \f$ (e_1,\ldots,e_p) \f$ is the canonical basis, we have: * \f[ P_\sigma(e_i) = e_{\sigma(i)}. \f] @@ -44,31 +46,29 @@ * Permutation matrices are square and invertible. * * Notice that in addition to the member functions and operators listed here, there also are non-member - * operator* to multiply a PermutationMatrix with any kind of matrix expression (MatrixBase) on either side. + * operator* to multiply any kind of permutation object with any kind of matrix expression (MatrixBase) + * on either side. * - * \sa class DiagonalMatrix + * \sa class PermutationMatrix, class PermutationWrapper */ namespace internal { -template<typename PermutationType, typename MatrixType, int Side, bool Transposed=false> struct permut_matrix_product_retval; - -template<int SizeAtCompileTime, int MaxSizeAtCompileTime> -struct traits<PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime> > - : traits<Matrix<int,SizeAtCompileTime,SizeAtCompileTime,0,MaxSizeAtCompileTime,MaxSizeAtCompileTime> > -{}; +template<typename PermutationType, typename MatrixType, int Side, bool Transposed=false> +struct permut_matrix_product_retval; +enum PermPermProduct_t {PermPermProduct}; } // end namespace internal -template<int SizeAtCompileTime, int MaxSizeAtCompileTime> -class PermutationMatrix : public EigenBase<PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime> > +template<typename Derived> +class PermutationBase : public EigenBase<Derived> { + typedef internal::traits<Derived> Traits; + typedef EigenBase<Derived> Base; public: #ifndef EIGEN_PARSED_BY_DOXYGEN - typedef internal::traits<PermutationMatrix> Traits; - typedef Matrix<int,SizeAtCompileTime,SizeAtCompileTime,0,MaxSizeAtCompileTime,MaxSizeAtCompileTime> - DenseMatrixType; + typedef typename Traits::IndicesType IndicesType; enum { Flags = Traits::Flags, CoeffReadCost = Traits::CoeffReadCost, @@ -79,85 +79,54 @@ class PermutationMatrix : public EigenBase<PermutationMatrix<SizeAtCompileTime, }; typedef typename Traits::Scalar Scalar; typedef typename Traits::Index Index; + typedef Matrix<Scalar,RowsAtCompileTime,ColsAtCompileTime,0,MaxRowsAtCompileTime,MaxColsAtCompileTime> + DenseMatrixType; + typedef PermutationMatrix<IndicesType::SizeAtCompileTime,IndicesType::MaxSizeAtCompileTime,Index> + PlainPermutationType; + using Base::derived; #endif - 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> - inline PermutationMatrix(const PermutationMatrix<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 PermutationMatrix(const PermutationMatrix& other) : m_indices(other.indices()) {} - #endif - - /** Generic constructor from expression of the indices. The indices - * array has the meaning that the permutations sends each integer i to indices[i]. - * - * \warning It is your responsibility to check that the indices array that you passes actually - * describes a permutation, i.e., each value between 0 and n-1 occurs exactly once, where n is the - * array's size. - */ - template<typename Other> - 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; - } + inline PermutationBase() {} /** Copies the other permutation into *this */ - template<int OtherSize, int OtherMaxSize> - PermutationMatrix& operator=(const PermutationMatrix<OtherSize, OtherMaxSize>& other) + template<typename OtherDerived> + Derived& operator=(const PermutationBase<OtherDerived>& other) { - m_indices = other.indices(); - return *this; + indices() = other.indices(); + return derived(); } /** Assignment from the Transpositions \a tr */ - template<int OtherSize, int OtherMaxSize> - PermutationMatrix& operator=(const Transpositions<OtherSize,OtherMaxSize>& tr) + template<typename OtherDerived> + Derived& operator=(const TranspositionsBase<OtherDerived>& tr) { setIdentity(tr.size()); for(Index k=size()-1; k>=0; --k) applyTranspositionOnTheRight(k,tr.coeff(k)); - return *this; + return derived(); } #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=. */ - PermutationMatrix& operator=(const PermutationMatrix& other) + Derived& operator=(const PermutationBase& other) { - m_indices = other.m_indices; - return *this; + indices() = other.indices(); + return derived(); } #endif /** \returns the number of rows */ - inline Index rows() const { return m_indices.size(); } + inline Index rows() const { return indices().size(); } /** \returns the number of columns */ - inline Index cols() const { return m_indices.size(); } + inline Index cols() const { return indices().size(); } /** \returns the size of a side of the respective square matrix, i.e., the number of indices */ - inline Index size() const { return m_indices.size(); } + inline Index size() const { return indices().size(); } #ifndef EIGEN_PARSED_BY_DOXYGEN template<typename DenseDerived> @@ -165,7 +134,7 @@ class PermutationMatrix : public EigenBase<PermutationMatrix<SizeAtCompileTime, { other.setZero(); for (int i=0; i<rows();++i) - other.coeffRef(m_indices.coeff(i),i) = typename DenseDerived::Scalar(1); + other.coeffRef(indices().coeff(i),i) = typename DenseDerived::Scalar(1); } #endif @@ -175,26 +144,26 @@ class PermutationMatrix : public EigenBase<PermutationMatrix<SizeAtCompileTime, */ DenseMatrixType toDenseMatrix() const { - return *this; + return derived(); } /** const version of indices(). */ - const IndicesType& indices() const { return m_indices; } + const IndicesType& indices() const { return derived().indices(); } /** \returns a reference to the stored array representing the permutation. */ - IndicesType& indices() { return m_indices; } + IndicesType& indices() { return derived().indices(); } /** Resizes to given size. */ inline void resize(Index size) { - m_indices.resize(size); + indices().resize(size); } /** Sets *this to be the identity permutation matrix */ void setIdentity() { - for(Index i = 0; i < m_indices.size(); ++i) - m_indices.coeffRef(i) = i; + for(Index i = 0; i < size(); ++i) + indices().coeffRef(i) = i; } /** Sets *this to be the identity permutation matrix of given size. @@ -214,15 +183,15 @@ class PermutationMatrix : public EigenBase<PermutationMatrix<SizeAtCompileTime, * * \sa applyTranspositionOnTheRight(int,int) */ - PermutationMatrix& applyTranspositionOnTheLeft(Index i, Index j) + Derived& applyTranspositionOnTheLeft(Index i, Index j) { - eigen_assert(i>=0 && j>=0 && i<m_indices.size() && j<m_indices.size()); - for(Index k = 0; k < m_indices.size(); ++k) + eigen_assert(i>=0 && j>=0 && i<size() && j<size()); + for(Index k = 0; k < size(); ++k) { - if(m_indices.coeff(k) == i) m_indices.coeffRef(k) = j; - else if(m_indices.coeff(k) == j) m_indices.coeffRef(k) = i; + if(indices().coeff(k) == i) indices().coeffRef(k) = j; + else if(indices().coeff(k) == j) indices().coeffRef(k) = i; } - return *this; + return derived(); } /** Multiplies *this by the transposition \f$(ij)\f$ on the right. @@ -233,42 +202,41 @@ class PermutationMatrix : public EigenBase<PermutationMatrix<SizeAtCompileTime, * * \sa applyTranspositionOnTheLeft(int,int) */ - PermutationMatrix& applyTranspositionOnTheRight(Index i, Index j) + Derived& applyTranspositionOnTheRight(Index i, Index j) { - eigen_assert(i>=0 && j>=0 && i<m_indices.size() && j<m_indices.size()); - std::swap(m_indices.coeffRef(i), m_indices.coeffRef(j)); - return *this; + eigen_assert(i>=0 && j>=0 && i<size() && j<size()); + std::swap(indices().coeffRef(i), indices().coeffRef(j)); + return derived(); } /** \returns the inverse permutation matrix. * * \note \note_try_to_help_rvo */ - inline Transpose<PermutationMatrix> inverse() const - { return *this; } + inline Transpose<PermutationBase> inverse() const + { return derived(); } /** \returns the tranpose permutation matrix. * * \note \note_try_to_help_rvo */ - inline Transpose<PermutationMatrix> transpose() const - { return *this; } + inline Transpose<PermutationBase> transpose() const + { return derived(); } /**** multiplication helpers to hopefully get RVO ****/ + #ifndef EIGEN_PARSED_BY_DOXYGEN - template<int OtherSize, int OtherMaxSize> - PermutationMatrix(const Transpose<PermutationMatrix<OtherSize,OtherMaxSize> >& other) - : m_indices(other.nestedPermutation().size()) + protected: + template<typename OtherDerived> + void assignTranspose(const PermutationBase<OtherDerived>& other) { - for (int i=0; i<rows();++i) m_indices.coeffRef(other.nestedPermutation().indices().coeff(i)) = i; + for (int i=0; i<rows();++i) indices().coeffRef(other.indices().coeff(i)) = i; } - protected: - enum Product_t {Product}; - PermutationMatrix(Product_t, const PermutationMatrix& lhs, const PermutationMatrix& rhs) - : m_indices(lhs.m_indices.size()) + template<typename Lhs,typename Rhs> + void assignProduct(const Lhs& lhs, const Rhs& rhs) { eigen_assert(lhs.cols() == rhs.rows()); - for (int i=0; i<rows();++i) m_indices.coeffRef(i) = lhs.m_indices.coeff(rhs.m_indices.coeff(i)); + for (int i=0; i<rows();++i) indices().coeffRef(i) = lhs.indices().coeff(rhs.indices().coeff(i)); } #endif @@ -278,54 +246,301 @@ class PermutationMatrix : public EigenBase<PermutationMatrix<SizeAtCompileTime, * * \note \note_try_to_help_rvo */ - template<int OtherSize, int OtherMaxSize> - inline PermutationMatrix operator*(const PermutationMatrix<OtherSize, OtherMaxSize>& other) const - { return PermutationMatrix(Product, *this, other); } + template<typename Other> + inline PlainPermutationType operator*(const PermutationBase<Other>& other) const + { return PlainPermutationType(internal::PermPermProduct, derived(), other.derived()); } /** \returns the product of a permutation with another inverse permutation. * * \note \note_try_to_help_rvo */ - template<int OtherSize, int OtherMaxSize> - inline PermutationMatrix operator*(const Transpose<PermutationMatrix<OtherSize,OtherMaxSize> >& other) const - { return PermutationMatrix(Product, *this, other.eval()); } + template<typename Other> + inline PlainPermutationType operator*(const Transpose<PermutationBase<Other> >& other) const + { return PlainPermutationType(internal::PermPermProduct, *this, other.eval()); } /** \returns the product of an inverse permutation with another permutation. * * \note \note_try_to_help_rvo */ - template<int OtherSize, int OtherMaxSize> friend - inline PermutationMatrix operator*(const Transpose<PermutationMatrix<OtherSize,OtherMaxSize> >& other, const PermutationMatrix& perm) - { return PermutationMatrix(Product, other.eval(), perm); } + template<typename Other> friend + inline PlainPermutationType operator*(const Transpose<PermutationBase<Other> >& other, const PermutationBase& perm) + { return PlainPermutationType(internal::PermPermProduct, other.eval(), perm); } + + protected: + +}; + +/** \class PermutationMatrix + * \ingroup Core_Module + * + * \brief Permutation matrix + * + * \param SizeAtCompileTime the number of rows/cols, or Dynamic + * \param MaxSizeAtCompileTime the maximum number of rows/cols, or Dynamic. This optional parameter defaults to SizeAtCompileTime. Most of the time, you should not have to specify it. + * \param IndexType the interger type of the indices + * + * This class represents a permutation matrix, internally stored as a vector of integers. + * + * \sa class PermutationBase, class PermutationWrapper, class DiagonalMatrix + */ + +namespace internal { +template<int SizeAtCompileTime, int MaxSizeAtCompileTime, typename IndexType> +struct traits<PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime, IndexType> > + : traits<Matrix<IndexType,SizeAtCompileTime,SizeAtCompileTime,0,MaxSizeAtCompileTime,MaxSizeAtCompileTime> > +{ + typedef IndexType Index; + typedef Matrix<IndexType, SizeAtCompileTime, 1, 0, MaxSizeAtCompileTime, 1> IndicesType; +}; +} + +template<int SizeAtCompileTime, int MaxSizeAtCompileTime, typename IndexType> +class PermutationMatrix : public PermutationBase<PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime, IndexType> > +{ + typedef PermutationBase<PermutationMatrix> Base; + typedef internal::traits<PermutationMatrix> Traits; + public: + + #ifndef EIGEN_PARSED_BY_DOXYGEN + typedef typename Traits::IndicesType IndicesType; + #endif + + inline PermutationMatrix() + {} + + /** Constructs an uninitialized permutation matrix of given size. + */ + inline PermutationMatrix(int size) : m_indices(size) + {} + + /** Copy constructor. */ + template<typename OtherDerived> + inline PermutationMatrix(const PermutationBase<OtherDerived>& 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 PermutationMatrix(const PermutationMatrix& other) : m_indices(other.indices()) {} + #endif + + /** Generic constructor from expression of the indices. The indices + * array has the meaning that the permutations sends each integer i to indices[i]. + * + * \warning It is your responsibility to check that the indices array that you passes actually + * describes a permutation, i.e., each value between 0 and n-1 occurs exactly once, where n is the + * array's size. + */ + template<typename Other> + explicit inline PermutationMatrix(const MatrixBase<Other>& indices) : m_indices(indices) + {} + + /** Convert the Transpositions \a tr to a permutation matrix */ + template<typename Other> + explicit PermutationMatrix(const TranspositionsBase<Other>& tr) + : m_indices(tr.size()) + { + *this = tr; + } + + /** Copies the other permutation into *this */ + template<typename Other> + PermutationMatrix& operator=(const PermutationBase<Other>& other) + { + m_indices = other.indices(); + return *this; + } + + /** Assignment from the Transpositions \a tr */ + template<typename Other> + PermutationMatrix& operator=(const TranspositionsBase<Other>& tr) + { + return Base::operator=(tr.derived()); + } + + #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=. + */ + PermutationMatrix& operator=(const PermutationMatrix& other) + { + m_indices = other.m_indices; + return *this; + } + #endif + + /** const version of indices(). */ + const IndicesType& indices() const { return m_indices; } + /** \returns a reference to the stored array representing the permutation. */ + IndicesType& indices() { return m_indices; } + + + /**** multiplication helpers to hopefully get RVO ****/ + +#ifndef EIGEN_PARSED_BY_DOXYGEN + template<typename Other> + PermutationMatrix(const Transpose<PermutationBase<Other> >& other) + : m_indices(other.nestedPermutation().size()) + { + for (int i=0; i<m_indices.size();++i) m_indices.coeffRef(other.nestedPermutation().indices().coeff(i)) = i; + } + template<typename Lhs,typename Rhs> + PermutationMatrix(internal::PermPermProduct_t, const Lhs& lhs, const Rhs& rhs) + : m_indices(lhs.indices().size()) + { + Base::assignProduct(lhs,rhs); + } +#endif + + protected: + + IndicesType m_indices; +}; + + +namespace internal { +template<int SizeAtCompileTime, int MaxSizeAtCompileTime, typename IndexType, int _PacketAccess> +struct traits<Map<PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime, IndexType>,_PacketAccess> > + : traits<Matrix<IndexType,SizeAtCompileTime,SizeAtCompileTime,0,MaxSizeAtCompileTime,MaxSizeAtCompileTime> > +{ + typedef IndexType Index; + typedef Map<const Matrix<IndexType, SizeAtCompileTime, 1, 0, MaxSizeAtCompileTime, 1>, _PacketAccess> IndicesType; +}; +} + +template<int SizeAtCompileTime, int MaxSizeAtCompileTime, typename IndexType, int _PacketAccess> +class Map<PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime, IndexType>,_PacketAccess> + : public PermutationBase<Map<PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime, IndexType>,_PacketAccess> > +{ + typedef PermutationBase<Map> Base; + typedef internal::traits<Map> Traits; + public: + + #ifndef EIGEN_PARSED_BY_DOXYGEN + typedef typename Traits::IndicesType IndicesType; + typedef typename IndicesType::Scalar Index; + #endif + + inline Map(const Index* indices) + : m_indices(indices) + {} + + inline Map(const Index* indices, Index size) + : m_indices(indices,size) + {} + + /** Copies the other permutation into *this */ + template<typename Other> + Map& operator=(const PermutationBase<Other>& other) + { return Base::operator=(other.derived()); } + + /** Assignment from the Transpositions \a tr */ + template<typename Other> + Map& operator=(const TranspositionsBase<Other>& tr) + { return Base::operator=(tr.derived()); } + + #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=. + */ + Map& operator=(const Map& other) + { + m_indices = other.m_indices; + return *this; + } + #endif + + /** const version of indices(). */ + const IndicesType& indices() const { return m_indices; } + /** \returns a reference to the stored array representing the permutation. */ + IndicesType& indices() { return m_indices; } protected: IndicesType m_indices; }; +/** \class PermutationWrapper + * \ingroup Core_Module + * + * \brief Class to view a vector of integers as a permutation matrix + * + * \param _IndicesType the type of the vector of integer (can be any compatible expression) + * + * This class allows to view any vector expression of integers as a permutation matrix. + * + * \sa class PermutationBase, class PermutationMatrix + */ + +struct PermutationStorage {}; + +template<typename _IndicesType> class TranspositionsWrapper; +namespace internal { +template<typename _IndicesType> +struct traits<PermutationWrapper<_IndicesType> > +{ + typedef PermutationStorage StorageKind; + typedef typename _IndicesType::Scalar Scalar; + typedef typename _IndicesType::Scalar Index; + typedef _IndicesType IndicesType; + enum { + RowsAtCompileTime = _IndicesType::SizeAtCompileTime, + ColsAtCompileTime = _IndicesType::SizeAtCompileTime, + MaxRowsAtCompileTime = IndicesType::MaxRowsAtCompileTime, + MaxColsAtCompileTime = IndicesType::MaxColsAtCompileTime, + Flags = 0, + CoeffReadCost = _IndicesType::CoeffReadCost + }; +}; +} + +template<typename _IndicesType> +class PermutationWrapper : public PermutationBase<PermutationWrapper<_IndicesType> > +{ + typedef PermutationBase<PermutationWrapper> Base; + typedef internal::traits<PermutationWrapper> Traits; + public: + + #ifndef EIGEN_PARSED_BY_DOXYGEN + typedef typename Traits::IndicesType IndicesType; + #endif + + inline PermutationWrapper(const IndicesType& indices) + : m_indices(indices) + {} + + /** const version of indices(). */ + const typename internal::remove_all<typename IndicesType::Nested>::type& + indices() const { return m_indices; } + + protected: + + const typename IndicesType::Nested m_indices; +}; + /** \returns the matrix with the permutation applied to the columns. */ -template<typename Derived, int SizeAtCompileTime, int MaxSizeAtCompileTime> -inline const internal::permut_matrix_product_retval<PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime>, Derived, OnTheRight> +template<typename Derived, typename PermutationDerived> +inline const internal::permut_matrix_product_retval<PermutationDerived, Derived, OnTheRight> operator*(const MatrixBase<Derived>& matrix, - const PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime> &permutation) + const PermutationBase<PermutationDerived> &permutation) { return internal::permut_matrix_product_retval - <PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime>, Derived, OnTheRight> - (permutation, matrix.derived()); + <PermutationDerived, Derived, OnTheRight> + (permutation.derived(), matrix.derived()); } /** \returns the matrix with the permutation applied to the rows. */ -template<typename Derived, int SizeAtCompileTime, int MaxSizeAtCompileTime> +template<typename Derived, typename PermutationDerived> inline const internal::permut_matrix_product_retval - <PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime>, Derived, OnTheLeft> -operator*(const PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime> &permutation, + <PermutationDerived, Derived, OnTheLeft> +operator*(const PermutationBase<PermutationDerived> &permutation, const MatrixBase<Derived>& matrix) { return internal::permut_matrix_product_retval - <PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime>, Derived, OnTheLeft> - (permutation, matrix.derived()); + <PermutationDerived, Derived, OnTheLeft> + (permutation.derived(), matrix.derived()); } namespace internal { @@ -402,25 +617,25 @@ struct permut_matrix_product_retval /* Template partial specialization for transposed/inverse permutations */ -template<int SizeAtCompileTime, int MaxSizeAtCompileTime> -struct traits<Transpose<PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime> > > - : traits<Matrix<int,SizeAtCompileTime,SizeAtCompileTime,0,MaxSizeAtCompileTime,MaxSizeAtCompileTime> > +template<typename Derived> +struct traits<Transpose<PermutationBase<Derived> > > + : traits<Derived> {}; } // end namespace internal -template<int SizeAtCompileTime, int MaxSizeAtCompileTime> -class Transpose<PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime> > - : public EigenBase<Transpose<PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime> > > +template<typename Derived> +class Transpose<PermutationBase<Derived> > + : public EigenBase<Transpose<PermutationBase<Derived> > > { - typedef PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime> PermutationType; + typedef Derived PermutationType; typedef typename PermutationType::IndicesType IndicesType; + typedef typename PermutationType::PlainPermutationType PlainPermutationType; public: #ifndef EIGEN_PARSED_BY_DOXYGEN typedef internal::traits<PermutationType> Traits; - typedef Matrix<int,SizeAtCompileTime,SizeAtCompileTime,0,MaxSizeAtCompileTime,MaxSizeAtCompileTime> - DenseMatrixType; + typedef typename Derived::DenseMatrixType DenseMatrixType; enum { Flags = Traits::Flags, CoeffReadCost = Traits::CoeffReadCost, @@ -448,26 +663,26 @@ class Transpose<PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime> > #endif /** \return the equivalent permutation matrix */ - PermutationType eval() const { return *this; } + PlainPermutationType eval() const { return *this; } DenseMatrixType toDenseMatrix() const { return *this; } /** \returns the matrix with the inverse permutation applied to the columns. */ - template<typename Derived> friend - inline const internal::permut_matrix_product_retval<PermutationType, Derived, OnTheRight, true> - operator*(const MatrixBase<Derived>& matrix, const Transpose& trPerm) + template<typename OtherDerived> friend + inline const internal::permut_matrix_product_retval<PermutationType, OtherDerived, OnTheRight, true> + operator*(const MatrixBase<OtherDerived>& matrix, const Transpose& trPerm) { - return internal::permut_matrix_product_retval<PermutationType, Derived, OnTheRight, true>(trPerm.m_permutation, matrix.derived()); + return internal::permut_matrix_product_retval<PermutationType, OtherDerived, OnTheRight, true>(trPerm.m_permutation, matrix.derived()); } /** \returns the matrix with the inverse permutation applied to the rows. */ - template<typename Derived> - inline const internal::permut_matrix_product_retval<PermutationType, Derived, OnTheLeft, true> - operator*(const MatrixBase<Derived>& matrix) const + template<typename OtherDerived> + inline const internal::permut_matrix_product_retval<PermutationType, OtherDerived, OnTheLeft, true> + operator*(const MatrixBase<OtherDerived>& matrix) const { - return internal::permut_matrix_product_retval<PermutationType, Derived, OnTheLeft, true>(m_permutation, matrix.derived()); + return internal::permut_matrix_product_retval<PermutationType, OtherDerived, OnTheLeft, true>(m_permutation, matrix.derived()); } const PermutationType& nestedPermutation() const { return m_permutation; } @@ -476,4 +691,10 @@ class Transpose<PermutationMatrix<SizeAtCompileTime, MaxSizeAtCompileTime> > const PermutationType& m_permutation; }; +template<typename Derived> +const PermutationWrapper<const Derived> MatrixBase<Derived>::asPermutation() const +{ + return derived(); +} + #endif // EIGEN_PERMUTATIONMATRIX_H diff --git a/Eigen/src/Core/Transpositions.h b/Eigen/src/Core/Transpositions.h index 9735b4eea..928ccb02b 100644 --- a/Eigen/src/Core/Transpositions.h +++ b/Eigen/src/Core/Transpositions.h @@ -1,7 +1,7 @@ // This file is part of Eigen, a lightweight C++ template library // for linear algebra. // -// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr> +// Copyright (C) 2010-2011 Gael Guennebaud <gael.guennebaud@inria.fr> // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -58,88 +58,72 @@ namespace internal { template<typename TranspositionType, typename MatrixType, int Side, bool Transposed=false> struct transposition_matrix_product_retval; } -template<int SizeAtCompileTime, int MaxSizeAtCompileTime> -class Transpositions +template<typename Derived> +class TranspositionsBase { + typedef internal::traits<Derived> Traits; + public: - typedef Matrix<DenseIndex, SizeAtCompileTime, 1, 0, MaxSizeAtCompileTime, 1> IndicesType; - typedef typename IndicesType::Index Index; + typedef typename Traits::IndicesType IndicesType; + typedef typename IndicesType::Scalar Index; - inline Transpositions() {} + Derived& derived() { return *static_cast<Derived*>(this); } + const Derived& derived() const { return *static_cast<const Derived*>(this); } - /** 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) - {} + inline TranspositionsBase() {} /** Copies the \a other transpositions into \c *this */ - template<int OtherSize, int OtherMaxSize> - Transpositions& operator=(const Transpositions<OtherSize, OtherMaxSize>& other) + template<typename OtherDerived> + Derived& operator=(const TranspositionsBase<OtherDerived>& other) { - m_indices = other.indices(); - return *this; + indices() = other.indices(); + return derived(); } #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) + Derived& operator=(const TranspositionsBase& other) { - m_indices = other.m_indices; - return *this; + indices() = other.indices(); + return derived(); } #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(); } + inline Index size() const { return indices().size(); } /** Direct access to the underlying index vector */ - inline const Index& coeff(Index i) const { return m_indices.coeff(i); } + inline const Index& coeff(Index i) const { return indices().coeff(i); } /** Direct access to the underlying index vector */ - inline Index& coeffRef(Index i) { return m_indices.coeffRef(i); } + inline Index& coeffRef(Index i) { return indices().coeffRef(i); } /** Direct access to the underlying index vector */ - inline const Index& operator()(Index i) const { return m_indices(i); } + inline const Index& operator()(Index i) const { return indices()(i); } /** Direct access to the underlying index vector */ - inline Index& operator()(Index i) { return m_indices(i); } + inline Index& operator()(Index i) { return indices()(i); } /** Direct access to the underlying index vector */ - inline const Index& operator[](Index i) const { return m_indices(i); } + inline const Index& operator[](Index i) const { return indices()(i); } /** Direct access to the underlying index vector */ - inline Index& operator[](Index i) { return m_indices(i); } + inline Index& operator[](Index i) { return indices()(i); } /** const version of indices(). */ - const IndicesType& indices() const { return m_indices; } + const IndicesType& indices() const { return derived().indices(); } /** \returns a reference to the stored array representing the transpositions. */ - IndicesType& indices() { return m_indices; } + IndicesType& indices() { return derived().indices(); } /** Resizes to given size. */ inline void resize(int size) { - m_indices.resize(size); + 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; + for(int i = 0; i < indices().size(); ++i) + coeffRef(i) = i; } // FIXME: do we want such methods ? @@ -164,53 +148,220 @@ class Transpositions */ /** \returns the inverse transformation */ - inline Transpose<Transpositions> inverse() const - { return *this; } + inline Transpose<TranspositionsBase> inverse() const + { return Transpose<TranspositionsBase>(derived()); } /** \returns the tranpose transformation */ - inline Transpose<Transpositions> transpose() const - { return *this; } + inline Transpose<TranspositionsBase> transpose() const + { return Transpose<TranspositionsBase>(derived()); } -#ifndef EIGEN_PARSED_BY_DOXYGEN - template<int OtherSize, int OtherMaxSize> - Transpositions(const Transpose<Transpositions<OtherSize,OtherMaxSize> >& other) - : m_indices(other.size()) + protected: +}; + +namespace internal { +template<int SizeAtCompileTime, int MaxSizeAtCompileTime, typename IndexType> +struct traits<Transpositions<SizeAtCompileTime,MaxSizeAtCompileTime,IndexType> > +{ + typedef IndexType Index; + typedef Matrix<Index, SizeAtCompileTime, 1, 0, MaxSizeAtCompileTime, 1> IndicesType; +}; +} + +template<int SizeAtCompileTime, int MaxSizeAtCompileTime, typename IndexType> +class Transpositions : public TranspositionsBase<Transpositions<SizeAtCompileTime,MaxSizeAtCompileTime,IndexType> > +{ + typedef internal::traits<Transpositions> Traits; + public: + + typedef TranspositionsBase<Transpositions> Base; + typedef typename Traits::IndicesType IndicesType; + typedef typename IndicesType::Scalar Index; + + inline Transpositions() {} + + /** Copy constructor. */ + template<typename OtherDerived> + inline Transpositions(const TranspositionsBase<OtherDerived>& 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<typename OtherDerived> + Transpositions& operator=(const TranspositionsBase<OtherDerived>& other) { - Index n = size(); - Index j = size-1; - for(Index i=0; i<n;++i,--j) - m_indices.coeffRef(j) = other.nestedTranspositions().indices().coeff(i); + return Base::operator=(other); } -#endif + + #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) + {} + + /** 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; } protected: IndicesType m_indices; }; + +namespace internal { +template<int SizeAtCompileTime, int MaxSizeAtCompileTime, typename IndexType, int _PacketAccess> +struct traits<Map<Transpositions<SizeAtCompileTime,MaxSizeAtCompileTime,IndexType>,_PacketAccess> > +{ + typedef IndexType Index; + typedef Map<const Matrix<Index,SizeAtCompileTime,1,0,MaxSizeAtCompileTime,1>, _PacketAccess> IndicesType; +}; +} + +template<int SizeAtCompileTime, int MaxSizeAtCompileTime, typename IndexType, int PacketAccess> +class Map<Transpositions<SizeAtCompileTime,MaxSizeAtCompileTime,IndexType>,PacketAccess> + : public TranspositionsBase<Map<Transpositions<SizeAtCompileTime,MaxSizeAtCompileTime,IndexType>,PacketAccess> > +{ + typedef internal::traits<Map> Traits; + public: + + typedef TranspositionsBase<Map> Base; + typedef typename Traits::IndicesType IndicesType; + typedef typename IndicesType::Scalar Index; + + inline Map(const Index* indices) + : m_indices(indices) + {} + + inline Map(const Index* indices, Index size) + : m_indices(indices,size) + {} + + /** Copies the \a other transpositions into \c *this */ + template<typename OtherDerived> + Map& operator=(const TranspositionsBase<OtherDerived>& other) + { + return Base::operator=(other); + } + + #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=. + */ + Map& operator=(const Map& other) + { + m_indices = other.m_indices; + return *this; + } + #endif + + /** 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; } + + protected: + + IndicesType m_indices; +}; + +namespace internal { +template<typename _IndicesType> +struct traits<TranspositionsWrapper<_IndicesType> > +{ + typedef typename _IndicesType::Scalar Index; + typedef _IndicesType IndicesType; +}; +} + +template<typename _IndicesType> +class TranspositionsWrapper + : public TranspositionsBase<TranspositionsWrapper<_IndicesType> > +{ + typedef internal::traits<TranspositionsWrapper> Traits; + public: + + typedef TranspositionsBase<TranspositionsWrapper> Base; + typedef typename Traits::IndicesType IndicesType; + typedef typename IndicesType::Scalar Index; + + inline TranspositionsWrapper(IndicesType& indices) + : m_indices(indices) + {} + + /** Copies the \a other transpositions into \c *this */ + template<typename OtherDerived> + TranspositionsWrapper& operator=(const TranspositionsBase<OtherDerived>& other) + { + return Base::operator=(other); + } + + #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=. + */ + TranspositionsWrapper& operator=(const TranspositionsWrapper& other) + { + m_indices = other.m_indices; + return *this; + } + #endif + + /** 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; } + + protected: + + const typename IndicesType::Nested m_indices; +}; + /** \returns the \a matrix with the \a transpositions applied to the columns. */ -template<typename Derived, int SizeAtCompileTime, int MaxSizeAtCompileTime> -inline const internal::transposition_matrix_product_retval<Transpositions<SizeAtCompileTime, MaxSizeAtCompileTime>, Derived, OnTheRight> +template<typename Derived, typename TranspositionsDerived> +inline const internal::transposition_matrix_product_retval<TranspositionsDerived, Derived, OnTheRight> operator*(const MatrixBase<Derived>& matrix, - const Transpositions<SizeAtCompileTime, MaxSizeAtCompileTime> &transpositions) + const TranspositionsBase<TranspositionsDerived> &transpositions) { return internal::transposition_matrix_product_retval - <Transpositions<SizeAtCompileTime, MaxSizeAtCompileTime>, Derived, OnTheRight> - (transpositions, matrix.derived()); + <TranspositionsDerived, Derived, OnTheRight> + (transpositions.derived(), matrix.derived()); } /** \returns the \a matrix with the \a transpositions applied to the rows. */ -template<typename Derived, int SizeAtCompileTime, int MaxSizeAtCompileTime> +template<typename Derived, typename TranspositionDerived> inline const internal::transposition_matrix_product_retval - <Transpositions<SizeAtCompileTime, MaxSizeAtCompileTime>, Derived, OnTheLeft> -operator*(const Transpositions<SizeAtCompileTime, MaxSizeAtCompileTime> &transpositions, + <TranspositionDerived, Derived, OnTheLeft> +operator*(const TranspositionsBase<TranspositionDerived> &transpositions, const MatrixBase<Derived>& matrix) { return internal::transposition_matrix_product_retval - <Transpositions<SizeAtCompileTime, MaxSizeAtCompileTime>, Derived, OnTheLeft> - (transpositions, matrix.derived()); + <TranspositionDerived, Derived, OnTheLeft> + (transpositions.derived(), matrix.derived()); } namespace internal { @@ -262,10 +413,10 @@ struct transposition_matrix_product_retval /* Template partial specialization for transposed/inverse transpositions */ -template<int SizeAtCompileTime, int MaxSizeAtCompileTime> -class Transpose<Transpositions<SizeAtCompileTime, MaxSizeAtCompileTime> > +template<typename TranspositionsDerived> +class Transpose<TranspositionsBase<TranspositionsDerived> > { - typedef Transpositions<SizeAtCompileTime, MaxSizeAtCompileTime> TranspositionType; + typedef TranspositionsDerived TranspositionType; typedef typename TranspositionType::IndicesType IndicesType; public: @@ -291,8 +442,6 @@ class Transpose<Transpositions<SizeAtCompileTime, MaxSizeAtCompileTime> > return internal::transposition_matrix_product_retval<TranspositionType, Derived, OnTheLeft, true>(m_transpositions, matrix.derived()); } - const TranspositionType& nestedTranspositions() const { return m_transpositions; } - protected: const TranspositionType& m_transpositions; }; diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 2a65c666d..d4eb2c31c 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -101,8 +101,12 @@ 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 = 0> class Diagonal; -template<int SizeAtCompileTime, int MaxSizeAtCompileTime = SizeAtCompileTime> class PermutationMatrix; -template<int SizeAtCompileTime, int MaxSizeAtCompileTime = SizeAtCompileTime> class Transpositions; +template<int SizeAtCompileTime, int MaxSizeAtCompileTime = SizeAtCompileTime, typename IndexType=int> class PermutationMatrix; +template<int SizeAtCompileTime, int MaxSizeAtCompileTime = SizeAtCompileTime, typename IndexType=int> class Transpositions; +template<typename Derived> class PermutationBase; +template<typename Derived> class TranspositionsBase; +template<typename _IndicesType> class PermutationWrapper; +template<typename _IndicesType> class TranspositionsWrapper; template<typename Derived, int Level = internal::accessors_level<Derived>::has_write_access ? WriteAccessors : ReadOnlyAccessors diff --git a/Eigen/src/LU/PartialPivLU.h b/Eigen/src/LU/PartialPivLU.h index 8694abae7..f9e645ec1 100644 --- a/Eigen/src/LU/PartialPivLU.h +++ b/Eigen/src/LU/PartialPivLU.h @@ -225,7 +225,7 @@ PartialPivLU<MatrixType>::PartialPivLU(const MatrixType& matrix) namespace internal { /** \internal This is the blocked version of fullpivlu_unblocked() */ -template<typename Scalar, int StorageOrder, typename PivIndex=DenseIndex> +template<typename Scalar, int StorageOrder, typename PivIndex> struct partial_lu_impl { // FIXME add a stride to Map, so that the following mapping becomes easier, @@ -384,13 +384,13 @@ struct partial_lu_impl /** \internal performs the LU decomposition with partial pivoting in-place. */ template<typename MatrixType, typename TranspositionType> -void partial_lu_inplace(MatrixType& lu, TranspositionType& row_transpositions, typename MatrixType::Index& nb_transpositions) +void partial_lu_inplace(MatrixType& lu, TranspositionType& row_transpositions, typename TranspositionType::Index& nb_transpositions) { eigen_assert(lu.cols() == row_transpositions.size()); eigen_assert((&row_transpositions.coeffRef(1)-&row_transpositions.coeffRef(0)) == 1); partial_lu_impl - <typename MatrixType::Scalar, MatrixType::Flags&RowMajorBit?RowMajor:ColMajor> + <typename MatrixType::Scalar, MatrixType::Flags&RowMajorBit?RowMajor:ColMajor, typename TranspositionType::Index> ::blocked_lu(lu.rows(), lu.cols(), &lu.coeffRef(0,0), lu.outerStride(), &row_transpositions.coeffRef(0), nb_transpositions); } @@ -406,7 +406,7 @@ PartialPivLU<MatrixType>& PartialPivLU<MatrixType>::compute(const MatrixType& ma m_rowsTranspositions.resize(size); - Index nb_transpositions; + typename TranspositionType::Index nb_transpositions; internal::partial_lu_inplace(m_lu, m_rowsTranspositions, nb_transpositions); m_det_p = (nb_transpositions%2) ? -1 : 1; diff --git a/test/permutationmatrices.cpp b/test/permutationmatrices.cpp index b9b3bbbca..d0fa01310 100644 --- a/test/permutationmatrices.cpp +++ b/test/permutationmatrices.cpp @@ -51,8 +51,10 @@ template<typename MatrixType> void permutationmatrices(const MatrixType& m) Options = MatrixType::Options }; typedef PermutationMatrix<Rows> LeftPermutationType; typedef Matrix<int, Rows, 1> LeftPermutationVectorType; + typedef Map<LeftPermutationType> MapLeftPerm; typedef PermutationMatrix<Cols> RightPermutationType; typedef Matrix<int, Cols, 1> RightPermutationVectorType; + typedef Map<RightPermutationType> MapRightPerm; Index rows = m.rows(); Index cols = m.cols(); @@ -76,13 +78,20 @@ template<typename MatrixType> void permutationmatrices(const MatrixType& m) VERIFY_IS_APPROX(m_permuted, lm*m_original*rm); VERIFY_IS_APPROX(lp.inverse()*m_permuted*rp.inverse(), m_original); + VERIFY_IS_APPROX(lv.asPermutation().inverse()*m_permuted*rv.asPermutation().inverse(), m_original); + VERIFY_IS_APPROX(MapLeftPerm(lv.data(),lv.size()).inverse()*m_permuted*MapRightPerm(rv.data(),rv.size()).inverse(), m_original); + VERIFY((lp*lp.inverse()).toDenseMatrix().isIdentity()); + VERIFY((lv.asPermutation()*lv.asPermutation().inverse()).toDenseMatrix().isIdentity()); + VERIFY((MapLeftPerm(lv.data(),lv.size())*MapLeftPerm(lv.data(),lv.size()).inverse()).toDenseMatrix().isIdentity()); LeftPermutationVectorType lv2; randomPermutationVector(lv2, rows); LeftPermutationType lp2(lv2); Matrix<Scalar,Rows,Rows> lm2(lp2); VERIFY_IS_APPROX((lp*lp2).toDenseMatrix().template cast<Scalar>(), lm*lm2); + VERIFY_IS_APPROX((lv.asPermutation()*lv2.asPermutation()).toDenseMatrix().template cast<Scalar>(), lm*lm2); + VERIFY_IS_APPROX((MapLeftPerm(lv.data(),lv.size())*MapLeftPerm(lv2.data(),lv2.size())).toDenseMatrix().template cast<Scalar>(), lm*lm2); LeftPermutationType identityp; identityp.setIdentity(rows); @@ -123,7 +132,7 @@ template<typename MatrixType> void permutationmatrices(const MatrixType& m) rm = rp; rm.col(i).swap(rm.col(j)); VERIFY_IS_APPROX(rm, rp2.toDenseMatrix().template cast<Scalar>()); - } + } } void test_permutationmatrices() |