bug #707: add inplace decomposition through Ref<> for Cholesky, LU and QR decompositions.

This commit is contained in:
Gael Guennebaud
2016-07-04 15:13:35 +02:00
parent 75e80792cc
commit 32a41ee659
10 changed files with 337 additions and 64 deletions

View File

@@ -97,6 +97,15 @@ template<typename _MatrixType> class FullPivLU
template<typename InputType>
explicit FullPivLU(const EigenBase<InputType>& matrix);
/** \brief Constructs a LU factorization from a given matrix
*
* This overloaded constructor is provided for inplace solving when \c MatrixType is a Eigen::Ref.
*
* \sa FullPivLU(const EigenBase&)
*/
template<typename InputType>
explicit FullPivLU(EigenBase<InputType>& matrix);
/** Computes the LU decomposition of the given matrix.
*
* \param matrix the matrix of which to compute the LU decomposition.
@@ -105,7 +114,11 @@ template<typename _MatrixType> class FullPivLU
* \returns a reference to *this
*/
template<typename InputType>
FullPivLU& compute(const EigenBase<InputType>& matrix);
FullPivLU& compute(const EigenBase<InputType>& matrix) {
m_lu = matrix.derived();
computeInPlace();
return *this;
}
/** \returns the LU decomposition matrix: the upper-triangular part is U, the
* unit-lower-triangular part is L (at least for square matrices; in the non-square
@@ -459,25 +472,28 @@ FullPivLU<MatrixType>::FullPivLU(const EigenBase<InputType>& matrix)
template<typename MatrixType>
template<typename InputType>
FullPivLU<MatrixType>& FullPivLU<MatrixType>::compute(const EigenBase<InputType>& matrix)
FullPivLU<MatrixType>::FullPivLU(EigenBase<InputType>& matrix)
: m_lu(matrix.derived()),
m_p(matrix.rows()),
m_q(matrix.cols()),
m_rowsTranspositions(matrix.rows()),
m_colsTranspositions(matrix.cols()),
m_isInitialized(false),
m_usePrescribedThreshold(false)
{
check_template_parameters();
// the permutations are stored as int indices, so just to be sure:
eigen_assert(matrix.rows()<=NumTraits<int>::highest() && matrix.cols()<=NumTraits<int>::highest());
m_lu = matrix.derived();
m_l1_norm = m_lu.cwiseAbs().colwise().sum().maxCoeff();
computeInPlace();
m_isInitialized = true;
return *this;
}
template<typename MatrixType>
void FullPivLU<MatrixType>::computeInPlace()
{
check_template_parameters();
// the permutations are stored as int indices, so just to be sure:
eigen_assert(m_lu.rows()<=NumTraits<int>::highest() && m_lu.cols()<=NumTraits<int>::highest());
m_l1_norm = m_lu.cwiseAbs().colwise().sum().maxCoeff();
const Index size = m_lu.diagonalSize();
const Index rows = m_lu.rows();
const Index cols = m_lu.cols();
@@ -557,6 +573,8 @@ void FullPivLU<MatrixType>::computeInPlace()
m_q.applyTranspositionOnTheRight(k, m_colsTranspositions.coeff(k));
m_det_pq = (number_of_transpositions%2) ? -1 : 1;
m_isInitialized = true;
}
template<typename MatrixType>

View File

@@ -26,6 +26,17 @@ template<typename _MatrixType> struct traits<PartialPivLU<_MatrixType> >
};
};
template<typename T,typename Derived>
struct enable_if_ref;
// {
// typedef Derived type;
// };
template<typename T,typename Derived>
struct enable_if_ref<Ref<T>,Derived> {
typedef Derived type;
};
} // end namespace internal
/** \ingroup LU_Module
@@ -102,8 +113,29 @@ template<typename _MatrixType> class PartialPivLU
template<typename InputType>
explicit PartialPivLU(const EigenBase<InputType>& matrix);
/** Constructor for inplace decomposition
*
* \param matrix the matrix of which to compute the LU decomposition.
*
* If \c MatrixType is an Eigen::Ref, then the storage of \a matrix will be shared
* between \a matrix and \c *this and the decomposition will take place in-place.
* The memory of \a matrix will be used througrough the lifetime of \c *this. In
* particular, further calls to \c this->compute(A) will still operate on the memory
* of \a matrix meaning. This also implies that the sizes of \c A must match the
* ones of \a matrix.
*
* \warning The matrix should have full rank (e.g. if it's square, it should be invertible).
* If you need to deal with non-full rank, use class FullPivLU instead.
*/
template<typename InputType>
PartialPivLU& compute(const EigenBase<InputType>& matrix);
explicit PartialPivLU(EigenBase<InputType>& matrix);
template<typename InputType>
PartialPivLU& compute(const EigenBase<InputType>& matrix) {
m_lu = matrix.derived();
compute();
return *this;
}
/** \returns the LU decomposition matrix: the upper-triangular part is U, the
* unit-lower-triangular part is L (at least for square matrices; in the non-square
@@ -251,6 +283,8 @@ template<typename _MatrixType> class PartialPivLU
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
}
void compute();
MatrixType m_lu;
PermutationType m_p;
TranspositionType m_rowsTranspositions;
@@ -284,7 +318,7 @@ PartialPivLU<MatrixType>::PartialPivLU(Index size)
template<typename MatrixType>
template<typename InputType>
PartialPivLU<MatrixType>::PartialPivLU(const EigenBase<InputType>& matrix)
: m_lu(matrix.rows(), matrix.rows()),
: m_lu(matrix.rows(),matrix.cols()),
m_p(matrix.rows()),
m_rowsTranspositions(matrix.rows()),
m_l1_norm(0),
@@ -294,6 +328,19 @@ PartialPivLU<MatrixType>::PartialPivLU(const EigenBase<InputType>& matrix)
compute(matrix.derived());
}
template<typename MatrixType>
template<typename InputType>
PartialPivLU<MatrixType>::PartialPivLU(EigenBase<InputType>& matrix)
: m_lu(matrix.derived()),
m_p(matrix.rows()),
m_rowsTranspositions(matrix.rows()),
m_l1_norm(0),
m_det_p(0),
m_isInitialized(false)
{
compute();
}
namespace internal {
/** \internal This is the blocked version of fullpivlu_unblocked() */
@@ -470,19 +517,17 @@ void partial_lu_inplace(MatrixType& lu, TranspositionType& row_transpositions, t
} // end namespace internal
template<typename MatrixType>
template<typename InputType>
PartialPivLU<MatrixType>& PartialPivLU<MatrixType>::compute(const EigenBase<InputType>& matrix)
void PartialPivLU<MatrixType>::compute()
{
check_template_parameters();
// the row permutation is stored as int indices, so just to be sure:
eigen_assert(matrix.rows()<NumTraits<int>::highest());
eigen_assert(m_lu.rows()<NumTraits<int>::highest());
m_lu = matrix.derived();
m_l1_norm = m_lu.cwiseAbs().colwise().sum().maxCoeff();
eigen_assert(matrix.rows() == matrix.cols() && "PartialPivLU is only for square (and moreover invertible) matrices");
const Index size = matrix.rows();
eigen_assert(m_lu.rows() == m_lu.cols() && "PartialPivLU is only for square (and moreover invertible) matrices");
const Index size = m_lu.rows();
m_rowsTranspositions.resize(size);
@@ -493,7 +538,6 @@ PartialPivLU<MatrixType>& PartialPivLU<MatrixType>::compute(const EigenBase<Inpu
m_p = m_rowsTranspositions;
m_isInitialized = true;
return *this;
}
template<typename MatrixType>