Oops, here the actual LLT and LDLT patch.

This commit is contained in:
Hauke Heibel 2009-05-22 15:58:20 +02:00
parent 0523b64fe9
commit c7303a876f
3 changed files with 80 additions and 26 deletions

View File

@ -62,16 +62,29 @@ template<typename MatrixType> class LDLT
typedef Matrix<int, MatrixType::RowsAtCompileTime, 1> IntColVectorType; typedef Matrix<int, MatrixType::RowsAtCompileTime, 1> IntColVectorType;
typedef Matrix<int, 1, MatrixType::RowsAtCompileTime> IntRowVectorType; typedef Matrix<int, 1, MatrixType::RowsAtCompileTime> IntRowVectorType;
/**
* \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(const MatrixType& matrix) LDLT(const MatrixType& matrix)
: m_matrix(matrix.rows(), matrix.cols()), : m_matrix(matrix.rows(), matrix.cols()),
m_p(matrix.rows()), m_p(matrix.rows()),
m_transpositions(matrix.rows()) m_transpositions(matrix.rows()),
m_isInitialized(false)
{ {
compute(matrix); compute(matrix);
} }
/** \returns the lower triangular matrix L */ /** \returns the lower triangular matrix L */
inline Part<MatrixType, UnitLowerTriangular> matrixL(void) const { return m_matrix; } inline Part<MatrixType, UnitLowerTriangular> matrixL(void) const
{
ei_assert(m_isInitialized && "LDLT is not initialized.");
return m_matrix;
}
/** \returns a vector of integers, whose size is the number of rows of the matrix being decomposed, /** \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, * representing the P permutation i.e. the permutation of the rows. For its precise meaning,
@ -79,17 +92,30 @@ template<typename MatrixType> class LDLT
*/ */
inline const IntColVectorType& permutationP() const inline const IntColVectorType& permutationP() const
{ {
ei_assert(m_isInitialized && "LDLT is not initialized.");
return m_p; return m_p;
} }
/** \returns the coefficients of the diagonal matrix D */ /** \returns the coefficients of the diagonal matrix D */
inline Diagonal<MatrixType,0> vectorD(void) const { return m_matrix.diagonal(); } inline Diagonal<MatrixType,0> vectorD(void) const
{
ei_assert(m_isInitialized && "LDLT is not initialized.");
return m_matrix.diagonal();
}
/** \returns true if the matrix is positive (semidefinite) */ /** \returns true if the matrix is positive (semidefinite) */
inline bool isPositive(void) const { return m_sign == 1; } inline bool isPositive(void) const
{
ei_assert(m_isInitialized && "LDLT is not initialized.");
return m_sign == 1;
}
/** \returns true if the matrix is negative (semidefinite) */ /** \returns true if the matrix is negative (semidefinite) */
inline bool isNegative(void) const { return m_sign == -1; } inline bool isNegative(void) const
{
ei_assert(m_isInitialized && "LDLT is not initialized.");
return m_sign == -1;
}
template<typename RhsDerived, typename ResDerived> template<typename RhsDerived, typename ResDerived>
bool solve(const MatrixBase<RhsDerived> &b, MatrixBase<ResDerived> *result) const; bool solve(const MatrixBase<RhsDerived> &b, MatrixBase<ResDerived> *result) const;
@ -110,6 +136,7 @@ template<typename MatrixType> class LDLT
IntColVectorType m_p; IntColVectorType m_p;
IntColVectorType m_transpositions; IntColVectorType m_transpositions;
int m_sign; int m_sign;
bool m_isInitialized;
}; };
/** Compute / recompute the LDLT decomposition A = L D L^* = U^* D U of \a matrix /** Compute / recompute the LDLT decomposition A = L D L^* = U^* D U of \a matrix
@ -126,6 +153,7 @@ void LDLT<MatrixType>::compute(const MatrixType& a)
m_p.setZero(); m_p.setZero();
m_transpositions.setZero(); m_transpositions.setZero();
m_sign = ei_real(a.coeff(0,0))>0 ? 1:-1; m_sign = ei_real(a.coeff(0,0))>0 ? 1:-1;
m_isInitialized = true;
return; return;
} }
@ -205,6 +233,8 @@ void LDLT<MatrixType>::compute(const MatrixType& a)
for(int k = size-1; k >= 0; --k) { for(int k = size-1; k >= 0; --k) {
std::swap(m_p.coeffRef(k), m_p.coeffRef(m_transpositions.coeff(k))); std::swap(m_p.coeffRef(k), m_p.coeffRef(m_transpositions.coeff(k)));
} }
m_isInitialized = true;
} }
/** Computes the solution x of \f$ A x = b \f$ using the current decomposition of A. /** Computes the solution x of \f$ A x = b \f$ using the current decomposition of A.
@ -222,6 +252,7 @@ template<typename RhsDerived, typename ResDerived>
bool LDLT<MatrixType> bool LDLT<MatrixType>
::solve(const MatrixBase<RhsDerived> &b, MatrixBase<ResDerived> *result) const ::solve(const MatrixBase<RhsDerived> &b, MatrixBase<ResDerived> *result) const
{ {
ei_assert(m_isInitialized && "LDLT is not initialized.");
const int size = m_matrix.rows(); const int size = m_matrix.rows();
ei_assert(size==b.rows() && "LDLT::solve(): invalid number of rows of the right hand side matrix b"); ei_assert(size==b.rows() && "LDLT::solve(): invalid number of rows of the right hand side matrix b");
*result = b; *result = b;
@ -243,6 +274,7 @@ template<typename MatrixType>
template<typename Derived> template<typename Derived>
bool LDLT<MatrixType>::solveInPlace(MatrixBase<Derived> &bAndX) const bool LDLT<MatrixType>::solveInPlace(MatrixBase<Derived> &bAndX) const
{ {
ei_assert(m_isInitialized && "LDLT is not initialized.");
const int size = m_matrix.rows(); const int size = m_matrix.rows();
ei_assert(size == bAndX.rows()); ei_assert(size == bAndX.rows());

View File

@ -65,14 +65,27 @@ template<typename MatrixType> class LLT
public: public:
/**
* \brief Default Constructor.
*
* The default constructor is useful in cases in which the user intends to
* perform decompositions via LLT::compute(const MatrixType&).
*/
LLT() : m_matrix(), m_isInitialized(false) {}
LLT(const MatrixType& matrix) LLT(const MatrixType& matrix)
: m_matrix(matrix.rows(), matrix.cols()) : m_matrix(matrix.rows(), matrix.cols()),
m_isInitialized(false)
{ {
compute(matrix); compute(matrix);
} }
/** \returns the lower triangular matrix L */ /** \returns the lower triangular matrix L */
inline Part<MatrixType, LowerTriangular> matrixL(void) const { return m_matrix; } inline Part<MatrixType, LowerTriangular> matrixL(void) const
{
ei_assert(m_isInitialized && "LLT is not initialized.");
return m_matrix;
}
template<typename RhsDerived, typename ResDerived> template<typename RhsDerived, typename ResDerived>
bool solve(const MatrixBase<RhsDerived> &b, MatrixBase<ResDerived> *result) const; bool solve(const MatrixBase<RhsDerived> &b, MatrixBase<ResDerived> *result) const;
@ -88,6 +101,7 @@ template<typename MatrixType> class LLT
* The strict upper part is not used and even not initialized. * The strict upper part is not used and even not initialized.
*/ */
MatrixType m_matrix; MatrixType m_matrix;
bool m_isInitialized;
}; };
/** Computes / recomputes the Cholesky decomposition A = LL^* = U^*U of \a matrix /** Computes / recomputes the Cholesky decomposition A = LL^* = U^*U of \a matrix
@ -109,7 +123,10 @@ void LLT<MatrixType>::compute(const MatrixType& a)
x = ei_real(a.coeff(0,0)); x = ei_real(a.coeff(0,0));
m_matrix.coeffRef(0,0) = ei_sqrt(x); m_matrix.coeffRef(0,0) = ei_sqrt(x);
if(size==1) if(size==1)
{
m_isInitialized = true;
return; return;
}
m_matrix.col(0).end(size-1) = a.row(0).end(size-1).adjoint() / ei_real(m_matrix.coeff(0,0)); m_matrix.col(0).end(size-1) = a.row(0).end(size-1).adjoint() / ei_real(m_matrix.coeff(0,0));
for (int j = 1; j < size; ++j) for (int j = 1; j < size; ++j)
{ {
@ -130,6 +147,8 @@ void LLT<MatrixType>::compute(const MatrixType& a)
- m_matrix.col(j).end(endSize) ) / x; - m_matrix.col(j).end(endSize) ) / x;
} }
} }
m_isInitialized = true;
} }
/** Computes the solution x of \f$ A x = b \f$ using the current decomposition of A. /** Computes the solution x of \f$ A x = b \f$ using the current decomposition of A.
@ -149,6 +168,7 @@ template<typename MatrixType>
template<typename RhsDerived, typename ResDerived> template<typename RhsDerived, typename ResDerived>
bool LLT<MatrixType>::solve(const MatrixBase<RhsDerived> &b, MatrixBase<ResDerived> *result) const bool LLT<MatrixType>::solve(const MatrixBase<RhsDerived> &b, MatrixBase<ResDerived> *result) const
{ {
ei_assert(m_isInitialized && "LLT is not initialized.");
const int size = m_matrix.rows(); const int size = m_matrix.rows();
ei_assert(size==b.rows() && "LLT::solve(): invalid number of rows of the right hand side matrix b"); ei_assert(size==b.rows() && "LLT::solve(): invalid number of rows of the right hand side matrix b");
return solveInPlace((*result) = b); return solveInPlace((*result) = b);
@ -169,6 +189,7 @@ template<typename MatrixType>
template<typename Derived> template<typename Derived>
bool LLT<MatrixType>::solveInPlace(MatrixBase<Derived> &bAndX) const bool LLT<MatrixType>::solveInPlace(MatrixBase<Derived> &bAndX) const
{ {
ei_assert(m_isInitialized && "LLT is not initialized.");
const int size = m_matrix.rows(); const int size = m_matrix.rows();
ei_assert(size==bAndX.rows()); ei_assert(size==bAndX.rows());
matrixL().solveTriangularInPlace(bAndX); matrixL().solveTriangularInPlace(bAndX);

View File

@ -112,29 +112,25 @@ template<typename MatrixType> void cholesky(const MatrixType& m)
} }
template<typename Derived> template<typename MatrixType> void cholesky_verify_assert()
void doSomeRankPreservingOperations(Eigen::MatrixBase<Derived>& m)
{ {
typedef typename Derived::RealScalar RealScalar; MatrixType tmp;
for(int a = 0; a < 3*(m.rows()+m.cols()); a++)
{
RealScalar d = Eigen::ei_random<RealScalar>(-1,1);
int i = Eigen::ei_random<int>(0,m.rows()-1); // i is a random row number
int j;
do {
j = Eigen::ei_random<int>(0,m.rows()-1);
} while (i==j); // j is another one (must be different)
m.row(i) += d * m.row(j);
i = Eigen::ei_random<int>(0,m.cols()-1); // i is a random column number LLT<MatrixType> llt;
do { VERIFY_RAISES_ASSERT(llt.matrixL())
j = Eigen::ei_random<int>(0,m.cols()-1); VERIFY_RAISES_ASSERT(llt.solve(tmp,&tmp))
} while (i==j); // j is another one (must be different) VERIFY_RAISES_ASSERT(llt.solveInPlace(&tmp))
m.col(i) += d * m.col(j);
} LDLT<MatrixType> ldlt;
VERIFY_RAISES_ASSERT(ldlt.matrixL())
VERIFY_RAISES_ASSERT(ldlt.permutationP())
VERIFY_RAISES_ASSERT(ldlt.vectorD())
VERIFY_RAISES_ASSERT(ldlt.isPositive())
VERIFY_RAISES_ASSERT(ldlt.isNegative())
VERIFY_RAISES_ASSERT(ldlt.solve(tmp,&tmp))
VERIFY_RAISES_ASSERT(ldlt.solveInPlace(&tmp))
} }
void test_cholesky() void test_cholesky()
{ {
for(int i = 0; i < g_repeat; i++) { for(int i = 0; i < g_repeat; i++) {
@ -147,4 +143,9 @@ void test_cholesky()
CALL_SUBTEST( cholesky(MatrixXd(17,17)) ); CALL_SUBTEST( cholesky(MatrixXd(17,17)) );
CALL_SUBTEST( cholesky(MatrixXf(200,200)) ); CALL_SUBTEST( cholesky(MatrixXf(200,200)) );
} }
CALL_SUBTEST( cholesky_verify_assert<Matrix3f>() );
CALL_SUBTEST( cholesky_verify_assert<Matrix3d>() );
CALL_SUBTEST( cholesky_verify_assert<MatrixXf>() );
CALL_SUBTEST( cholesky_verify_assert<MatrixXd>() );
} }