mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-06-04 18:54:00 +08:00
bug #1268: detect faillure in LDLT and report them through info()
This commit is contained in:
parent
bde9b456dc
commit
8132a12625
@ -253,7 +253,7 @@ template<typename _MatrixType, int _UpLo> class LDLT
|
|||||||
ComputationInfo info() const
|
ComputationInfo info() const
|
||||||
{
|
{
|
||||||
eigen_assert(m_isInitialized && "LDLT is not initialized.");
|
eigen_assert(m_isInitialized && "LDLT is not initialized.");
|
||||||
return Success;
|
return m_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||||
@ -281,6 +281,7 @@ template<typename _MatrixType, int _UpLo> class LDLT
|
|||||||
TmpMatrixType m_temporary;
|
TmpMatrixType m_temporary;
|
||||||
internal::SignMatrix m_sign;
|
internal::SignMatrix m_sign;
|
||||||
bool m_isInitialized;
|
bool m_isInitialized;
|
||||||
|
ComputationInfo m_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
@ -298,6 +299,8 @@ template<> struct ldlt_inplace<Lower>
|
|||||||
typedef typename TranspositionType::StorageIndex IndexType;
|
typedef typename TranspositionType::StorageIndex IndexType;
|
||||||
eigen_assert(mat.rows()==mat.cols());
|
eigen_assert(mat.rows()==mat.cols());
|
||||||
const Index size = mat.rows();
|
const Index size = mat.rows();
|
||||||
|
bool found_zero_pivot = false;
|
||||||
|
bool ret = true;
|
||||||
|
|
||||||
if (size <= 1)
|
if (size <= 1)
|
||||||
{
|
{
|
||||||
@ -356,9 +359,27 @@ template<> struct ldlt_inplace<Lower>
|
|||||||
// we should only make sure that we do not introduce INF or NaN values.
|
// we should only make sure that we do not introduce INF or NaN values.
|
||||||
// Remark that LAPACK also uses 0 as the cutoff value.
|
// Remark that LAPACK also uses 0 as the cutoff value.
|
||||||
RealScalar realAkk = numext::real(mat.coeffRef(k,k));
|
RealScalar realAkk = numext::real(mat.coeffRef(k,k));
|
||||||
if((rs>0) && (abs(realAkk) > RealScalar(0)))
|
bool pivot_is_valid = (abs(realAkk) > RealScalar(0));
|
||||||
|
|
||||||
|
if(k==0 && !pivot_is_valid)
|
||||||
|
{
|
||||||
|
// The entire diagonal is zero, there is nothing more to do
|
||||||
|
// except filling the transpositions, and checking whether the matrix is zero.
|
||||||
|
sign = ZeroSign;
|
||||||
|
for(Index j = 0; j<size; ++j)
|
||||||
|
{
|
||||||
|
transpositions.coeffRef(j) = IndexType(j);
|
||||||
|
ret = ret && (mat.col(j).tail(size-j-1).array()==Scalar(0)).all();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((rs>0) && pivot_is_valid)
|
||||||
A21 /= realAkk;
|
A21 /= realAkk;
|
||||||
|
|
||||||
|
if(found_zero_pivot && pivot_is_valid) ret = false; // factorization failed
|
||||||
|
else if(!pivot_is_valid) found_zero_pivot = true;
|
||||||
|
|
||||||
if (sign == PositiveSemiDef) {
|
if (sign == PositiveSemiDef) {
|
||||||
if (realAkk < static_cast<RealScalar>(0)) sign = Indefinite;
|
if (realAkk < static_cast<RealScalar>(0)) sign = Indefinite;
|
||||||
} else if (sign == NegativeSemiDef) {
|
} else if (sign == NegativeSemiDef) {
|
||||||
@ -369,7 +390,7 @@ template<> struct ldlt_inplace<Lower>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reference for the algorithm: Davis and Hager, "Multiple Rank
|
// Reference for the algorithm: Davis and Hager, "Multiple Rank
|
||||||
@ -493,7 +514,7 @@ LDLT<MatrixType,_UpLo>& LDLT<MatrixType,_UpLo>::compute(const EigenBase<InputTyp
|
|||||||
m_temporary.resize(size);
|
m_temporary.resize(size);
|
||||||
m_sign = internal::ZeroSign;
|
m_sign = internal::ZeroSign;
|
||||||
|
|
||||||
internal::ldlt_inplace<UpLo>::unblocked(m_matrix, m_transpositions, m_temporary, m_sign);
|
m_info = internal::ldlt_inplace<UpLo>::unblocked(m_matrix, m_transpositions, m_temporary, m_sign) ? Success : NumericalIssue;
|
||||||
|
|
||||||
m_isInitialized = true;
|
m_isInitialized = true;
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -154,6 +154,7 @@ template<typename MatrixType> void cholesky(const MatrixType& m)
|
|||||||
SquareMatrixType symmLo = symm.template triangularView<Lower>();
|
SquareMatrixType symmLo = symm.template triangularView<Lower>();
|
||||||
|
|
||||||
LDLT<SquareMatrixType,Lower> ldltlo(symmLo);
|
LDLT<SquareMatrixType,Lower> ldltlo(symmLo);
|
||||||
|
VERIFY(ldltlo.info()==Success);
|
||||||
VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix());
|
VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix());
|
||||||
vecX = ldltlo.solve(vecB);
|
vecX = ldltlo.solve(vecB);
|
||||||
VERIFY_IS_APPROX(symm * vecX, vecB);
|
VERIFY_IS_APPROX(symm * vecX, vecB);
|
||||||
@ -170,6 +171,7 @@ template<typename MatrixType> void cholesky(const MatrixType& m)
|
|||||||
|
|
||||||
|
|
||||||
LDLT<SquareMatrixType,Upper> ldltup(symmUp);
|
LDLT<SquareMatrixType,Upper> ldltup(symmUp);
|
||||||
|
VERIFY(ldltup.info()==Success);
|
||||||
VERIFY_IS_APPROX(symm, ldltup.reconstructedMatrix());
|
VERIFY_IS_APPROX(symm, ldltup.reconstructedMatrix());
|
||||||
vecX = ldltup.solve(vecB);
|
vecX = ldltup.solve(vecB);
|
||||||
VERIFY_IS_APPROX(symm * vecX, vecB);
|
VERIFY_IS_APPROX(symm * vecX, vecB);
|
||||||
@ -331,6 +333,7 @@ template<typename MatrixType> void cholesky_cplx(const MatrixType& m)
|
|||||||
RealMatrixType symmLo = symm.template triangularView<Lower>();
|
RealMatrixType symmLo = symm.template triangularView<Lower>();
|
||||||
|
|
||||||
LDLT<RealMatrixType,Lower> ldltlo(symmLo);
|
LDLT<RealMatrixType,Lower> ldltlo(symmLo);
|
||||||
|
VERIFY(ldltlo.info()==Success);
|
||||||
VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix());
|
VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix());
|
||||||
vecX = ldltlo.solve(vecB);
|
vecX = ldltlo.solve(vecB);
|
||||||
VERIFY_IS_APPROX(symm * vecX, vecB);
|
VERIFY_IS_APPROX(symm * vecX, vecB);
|
||||||
@ -367,35 +370,88 @@ template<typename MatrixType> void cholesky_definiteness(const MatrixType& m)
|
|||||||
{
|
{
|
||||||
mat << 1, 0, 0, -1;
|
mat << 1, 0, 0, -1;
|
||||||
ldlt.compute(mat);
|
ldlt.compute(mat);
|
||||||
|
VERIFY(ldlt.info()==Success);
|
||||||
VERIFY(!ldlt.isNegative());
|
VERIFY(!ldlt.isNegative());
|
||||||
VERIFY(!ldlt.isPositive());
|
VERIFY(!ldlt.isPositive());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
mat << 1, 2, 2, 1;
|
mat << 1, 2, 2, 1;
|
||||||
ldlt.compute(mat);
|
ldlt.compute(mat);
|
||||||
|
VERIFY(ldlt.info()==Success);
|
||||||
VERIFY(!ldlt.isNegative());
|
VERIFY(!ldlt.isNegative());
|
||||||
VERIFY(!ldlt.isPositive());
|
VERIFY(!ldlt.isPositive());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
mat << 0, 0, 0, 0;
|
mat << 0, 0, 0, 0;
|
||||||
ldlt.compute(mat);
|
ldlt.compute(mat);
|
||||||
|
VERIFY(ldlt.info()==Success);
|
||||||
VERIFY(ldlt.isNegative());
|
VERIFY(ldlt.isNegative());
|
||||||
VERIFY(ldlt.isPositive());
|
VERIFY(ldlt.isPositive());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
mat << 0, 0, 0, 1;
|
mat << 0, 0, 0, 1;
|
||||||
ldlt.compute(mat);
|
ldlt.compute(mat);
|
||||||
|
VERIFY(ldlt.info()==Success);
|
||||||
VERIFY(!ldlt.isNegative());
|
VERIFY(!ldlt.isNegative());
|
||||||
VERIFY(ldlt.isPositive());
|
VERIFY(ldlt.isPositive());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
mat << -1, 0, 0, 0;
|
mat << -1, 0, 0, 0;
|
||||||
ldlt.compute(mat);
|
ldlt.compute(mat);
|
||||||
|
VERIFY(ldlt.info()==Success);
|
||||||
VERIFY(ldlt.isNegative());
|
VERIFY(ldlt.isNegative());
|
||||||
VERIFY(!ldlt.isPositive());
|
VERIFY(!ldlt.isPositive());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename>
|
||||||
|
void cholesky_faillure_cases()
|
||||||
|
{
|
||||||
|
MatrixXd mat;
|
||||||
|
LDLT<MatrixXd> ldlt;
|
||||||
|
|
||||||
|
{
|
||||||
|
mat.resize(2,2);
|
||||||
|
mat << 0, 1, 1, 0;
|
||||||
|
ldlt.compute(mat);
|
||||||
|
VERIFY_IS_NOT_APPROX(mat,ldlt.reconstructedMatrix());
|
||||||
|
VERIFY(ldlt.info()==NumericalIssue);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mat.resize(3,3);
|
||||||
|
mat << -1, -3, 3,
|
||||||
|
-3, -8.9999999999999999999, 1,
|
||||||
|
3, 1, 0;
|
||||||
|
ldlt.compute(mat);
|
||||||
|
VERIFY(ldlt.info()==NumericalIssue);
|
||||||
|
VERIFY_IS_NOT_APPROX(mat,ldlt.reconstructedMatrix());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
mat.resize(3,3);
|
||||||
|
mat << 1, 2, 3,
|
||||||
|
2, 4, 1,
|
||||||
|
3, 1, 0;
|
||||||
|
ldlt.compute(mat);
|
||||||
|
VERIFY(ldlt.info()==NumericalIssue);
|
||||||
|
VERIFY_IS_NOT_APPROX(mat,ldlt.reconstructedMatrix());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
mat.resize(8,8);
|
||||||
|
mat << 0.1, 0, -0.1, 0, 0, 0, 1, 0,
|
||||||
|
0, 4.24667, 0, 2.00333, 0, 0, 0, 0,
|
||||||
|
-0.1, 0, 0.2, 0, -0.1, 0, 0, 0,
|
||||||
|
0, 2.00333, 0, 8.49333, 0, 2.00333, 0, 0,
|
||||||
|
0, 0, -0.1, 0, 0.1, 0, 0, 1,
|
||||||
|
0, 0, 0, 2.00333, 0, 4.24667, 0, 0,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 1, 0, 0, 0;
|
||||||
|
ldlt.compute(mat);
|
||||||
|
VERIFY(ldlt.info()==NumericalIssue);
|
||||||
|
VERIFY_IS_NOT_APPROX(mat,ldlt.reconstructedMatrix());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename MatrixType> void cholesky_verify_assert()
|
template<typename MatrixType> void cholesky_verify_assert()
|
||||||
{
|
{
|
||||||
MatrixType tmp;
|
MatrixType tmp;
|
||||||
@ -445,5 +501,7 @@ void test_cholesky()
|
|||||||
CALL_SUBTEST_9( LLT<MatrixXf>(10) );
|
CALL_SUBTEST_9( LLT<MatrixXf>(10) );
|
||||||
CALL_SUBTEST_9( LDLT<MatrixXf>(10) );
|
CALL_SUBTEST_9( LDLT<MatrixXf>(10) );
|
||||||
|
|
||||||
|
CALL_SUBTEST_2( cholesky_faillure_cases<void>() );
|
||||||
|
|
||||||
TEST_SET_BUT_UNUSED_VARIABLE(nb_temporaries)
|
TEST_SET_BUT_UNUSED_VARIABLE(nb_temporaries)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user