Many improvements in LLT and LDLT:

* in LDLT, support the negative semidefinite case
* fix bad floating-point comparisons, improves greatly the accuracy of methods like
  isPositiveDefinite() and rank()
* simplifications
* identify (but not resolve) bug: claim that only triangular part is used, is inaccurate
* expanded unit-tests
This commit is contained in:
Benoit Jacob
2009-03-30 21:45:45 +00:00
parent df9dfa1455
commit a1ba995f05
3 changed files with 142 additions and 52 deletions

View File

@@ -41,10 +41,11 @@
* and even faster. Nevertheless, this standard Cholesky decomposition remains useful in many other
* situations like generalised eigen problems with hermitian matrices.
*
* \sa MatrixBase::llt(), class LDLT
*/
/* HEY THIS DOX IS DISABLED BECAUSE THERE's A BUG EITHER HERE OR IN LDLT ABOUT THAT (OR BOTH)
* 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.
*
* \sa MatrixBase::llt(), class LDLT
*/
template<typename MatrixType> class LLT
{
@@ -72,6 +73,9 @@ template<typename MatrixType> class LLT
/** \returns true if the matrix is positive definite */
inline bool isPositiveDefinite(void) const { return m_isPositiveDefinite; }
/** \returns true if the matrix is invertible, which in this context is equivalent to positive definite */
inline bool isInvertible(void) const { return m_isPositiveDefinite; }
template<typename RhsDerived, typename ResDerived>
bool solve(const MatrixBase<RhsDerived> &b, MatrixBase<ResDerived> *result) const;
@@ -97,11 +101,10 @@ void LLT<MatrixType>::compute(const MatrixType& a)
assert(a.rows()==a.cols());
const int size = a.rows();
m_matrix.resize(size, size);
const RealScalar eps = precision<Scalar>();
const RealScalar reference = size * a.diagonal().cwise().abs().maxCoeff();
RealScalar x;
x = ei_real(a.coeff(0,0));
m_isPositiveDefinite = x > eps && ei_isMuchSmallerThan(ei_imag(a.coeff(0,0)), RealScalar(1));
m_isPositiveDefinite = !ei_isMuchSmallerThan(x, reference) && ei_isMuchSmallerThan(ei_imag(a.coeff(0,0)), reference);
m_matrix.coeffRef(0,0) = ei_sqrt(x);
if(size==1)
return;
@@ -110,7 +113,7 @@ void LLT<MatrixType>::compute(const MatrixType& a)
{
Scalar tmp = ei_real(a.coeff(j,j)) - m_matrix.row(j).start(j).squaredNorm();
x = ei_real(tmp);
if (x < eps || (!ei_isMuchSmallerThan(ei_imag(tmp), RealScalar(1))))
if (ei_isMuchSmallerThan(x, reference) || (!ei_isMuchSmallerThan(ei_imag(tmp), reference)))
{
m_isPositiveDefinite = false;
return;