mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-06-01 23:24:06 +08:00
Fix deflation in BDCSVD.
This commit is contained in:
parent
f40ad38fda
commit
0b9ca1159b
@ -1126,13 +1126,6 @@ void BDCSVD<MatrixType, Options>::perturbCol0(const ArrayRef& col0, const ArrayR
|
|||||||
<< "j=" << j << "\n";
|
<< "j=" << j << "\n";
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// Avoid index out of bounds.
|
|
||||||
// Will end up setting zhat(k) = 0.
|
|
||||||
if (i >= k && l == 0) {
|
|
||||||
m_info = NumericalIssue;
|
|
||||||
prod = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Index j = i < k ? i : l > 0 ? perm(l - 1) : i;
|
Index j = i < k ? i : l > 0 ? perm(l - 1) : i;
|
||||||
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
||||||
if (!(dk != Literal(0) || diag(i) != Literal(0))) {
|
if (!(dk != Literal(0) || diag(i) != Literal(0))) {
|
||||||
@ -1205,7 +1198,7 @@ void BDCSVD<MatrixType, Options>::computeSingVecs(const ArrayRef& zhat, const Ar
|
|||||||
|
|
||||||
// page 12_13
|
// page 12_13
|
||||||
// i >= 1, di almost null and zi non null.
|
// i >= 1, di almost null and zi non null.
|
||||||
// We use a rotation to zero out zi applied to the left of M
|
// We use a rotation to zero out zi applied to the left of M, and set di = 0.
|
||||||
template <typename MatrixType, int Options>
|
template <typename MatrixType, int Options>
|
||||||
void BDCSVD<MatrixType, Options>::deflation43(Index firstCol, Index shift, Index i, Index size) {
|
void BDCSVD<MatrixType, Options>::deflation43(Index firstCol, Index shift, Index i, Index size) {
|
||||||
using std::abs;
|
using std::abs;
|
||||||
@ -1231,9 +1224,8 @@ void BDCSVD<MatrixType, Options>::deflation43(Index firstCol, Index shift, Index
|
|||||||
} // end deflation 43
|
} // end deflation 43
|
||||||
|
|
||||||
// page 13
|
// page 13
|
||||||
// i,j >= 1, i!=j and |di - dj| < epsilon * norm2(M)
|
// i,j >= 1, i > j, and |di - dj| < epsilon * norm2(M)
|
||||||
// We apply two rotations to have zj = 0;
|
// We apply two rotations to have zi = 0, and dj = di.
|
||||||
// TODO deflation44 is still broken and not properly tested
|
|
||||||
template <typename MatrixType, int Options>
|
template <typename MatrixType, int Options>
|
||||||
void BDCSVD<MatrixType, Options>::deflation44(Index firstColu, Index firstColm, Index firstRowW, Index firstColW,
|
void BDCSVD<MatrixType, Options>::deflation44(Index firstColu, Index firstColm, Index firstRowW, Index firstColW,
|
||||||
Index i, Index j, Index size) {
|
Index i, Index j, Index size) {
|
||||||
@ -1241,9 +1233,10 @@ void BDCSVD<MatrixType, Options>::deflation44(Index firstColu, Index firstColm,
|
|||||||
using std::conj;
|
using std::conj;
|
||||||
using std::pow;
|
using std::pow;
|
||||||
using std::sqrt;
|
using std::sqrt;
|
||||||
RealScalar c = m_computed(firstColm + i, firstColm);
|
|
||||||
RealScalar s = m_computed(firstColm + j, firstColm);
|
RealScalar s = m_computed(firstColm + i, firstColm);
|
||||||
RealScalar r = sqrt(numext::abs2(c) + numext::abs2(s));
|
RealScalar c = m_computed(firstColm + j, firstColm);
|
||||||
|
RealScalar r = numext::hypot(c, s);
|
||||||
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
||||||
std::cout << "deflation 4.4: " << i << "," << j << " -> " << c << " " << s << " " << r << " ; "
|
std::cout << "deflation 4.4: " << i << "," << j << " -> " << c << " " << s << " " << r << " ; "
|
||||||
<< m_computed(firstColm + i - 1, firstColm) << " " << m_computed(firstColm + i, firstColm) << " "
|
<< m_computed(firstColm + i - 1, firstColm) << " " << m_computed(firstColm + i, firstColm) << " "
|
||||||
@ -1253,21 +1246,21 @@ void BDCSVD<MatrixType, Options>::deflation44(Index firstColu, Index firstColm,
|
|||||||
<< m_computed(firstColm + i + 2, firstColm + i + 2) << "\n";
|
<< m_computed(firstColm + i + 2, firstColm + i + 2) << "\n";
|
||||||
#endif
|
#endif
|
||||||
if (numext::is_exactly_zero(r)) {
|
if (numext::is_exactly_zero(r)) {
|
||||||
m_computed(firstColm + i, firstColm + i) = m_computed(firstColm + j, firstColm + j);
|
m_computed(firstColm + j, firstColm + j) = m_computed(firstColm + i, firstColm + i);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
c /= r;
|
c /= r;
|
||||||
s /= r;
|
s /= r;
|
||||||
m_computed(firstColm + i, firstColm) = r;
|
m_computed(firstColm + j, firstColm) = r;
|
||||||
m_computed(firstColm + j, firstColm + j) = m_computed(firstColm + i, firstColm + i);
|
m_computed(firstColm + j, firstColm + j) = m_computed(firstColm + i, firstColm + i);
|
||||||
m_computed(firstColm + j, firstColm) = Literal(0);
|
m_computed(firstColm + i, firstColm) = Literal(0);
|
||||||
|
|
||||||
JacobiRotation<RealScalar> J(c, -s);
|
JacobiRotation<RealScalar> J(c, -s);
|
||||||
if (m_compU)
|
if (m_compU)
|
||||||
m_naiveU.middleRows(firstColu, size + 1).applyOnTheRight(firstColu + i, firstColu + j, J);
|
m_naiveU.middleRows(firstColu, size + 1).applyOnTheRight(firstColu + j, firstColu + i, J);
|
||||||
else
|
else
|
||||||
m_naiveU.applyOnTheRight(firstColu + i, firstColu + j, J);
|
m_naiveU.applyOnTheRight(firstColu + j, firstColu + i, J);
|
||||||
if (m_compV) m_naiveV.middleRows(firstRowW, size).applyOnTheRight(firstColW + i, firstColW + j, J);
|
if (m_compV) m_naiveV.middleRows(firstRowW, size).applyOnTheRight(firstColW + j, firstColW + i, J);
|
||||||
} // end deflation 44
|
} // end deflation 44
|
||||||
|
|
||||||
// acts on block from (firstCol+shift, firstCol+shift) to (lastCol+shift, lastCol+shift) [inclusive]
|
// acts on block from (firstCol+shift, firstCol+shift) to (lastCol+shift, lastCol+shift) [inclusive]
|
||||||
@ -1350,7 +1343,7 @@ void BDCSVD<MatrixType, Options>::deflation(Index firstCol, Index lastCol, Index
|
|||||||
|
|
||||||
// Move deflated diagonal entries at the end.
|
// Move deflated diagonal entries at the end.
|
||||||
for (Index i = 1; i < length; ++i)
|
for (Index i = 1; i < length; ++i)
|
||||||
if (abs(diag(i)) < considerZero) permutation[p++] = i;
|
if (diag(i) < considerZero) permutation[p++] = i;
|
||||||
|
|
||||||
Index i = 1, j = k + 1;
|
Index i = 1, j = k + 1;
|
||||||
for (; p < length; ++p) {
|
for (; p < length; ++p) {
|
||||||
@ -1369,7 +1362,7 @@ void BDCSVD<MatrixType, Options>::deflation(Index firstCol, Index lastCol, Index
|
|||||||
if (total_deflation) {
|
if (total_deflation) {
|
||||||
for (Index i = 1; i < length; ++i) {
|
for (Index i = 1; i < length; ++i) {
|
||||||
Index pi = permutation[i];
|
Index pi = permutation[i];
|
||||||
if (abs(diag(pi)) < considerZero || diag(0) < diag(pi))
|
if (diag(pi) < considerZero || diag(0) < diag(pi))
|
||||||
permutation[i - 1] = permutation[i];
|
permutation[i - 1] = permutation[i];
|
||||||
else {
|
else {
|
||||||
permutation[i - 1] = 0;
|
permutation[i - 1] = 0;
|
||||||
@ -1424,17 +1417,19 @@ void BDCSVD<MatrixType, Options>::deflation(Index firstCol, Index lastCol, Index
|
|||||||
// condition 4.4
|
// condition 4.4
|
||||||
{
|
{
|
||||||
Index i = length - 1;
|
Index i = length - 1;
|
||||||
while (i > 0 && (abs(diag(i)) < considerZero || abs(col0(i)) < considerZero)) --i;
|
// Find last non-deflated entry.
|
||||||
|
while (i > 0 && (diag(i) < considerZero || abs(col0(i)) < considerZero)) --i;
|
||||||
|
|
||||||
for (; i > 1; --i)
|
for (; i > 1; --i)
|
||||||
if ((diag(i) - diag(i - 1)) < NumTraits<RealScalar>::epsilon() * maxDiag) {
|
if ((diag(i) - diag(i - 1)) < epsilon_strict) {
|
||||||
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
||||||
std::cout << "deflation 4.4 with i = " << i << " because " << diag(i) << " - " << diag(i - 1)
|
std::cout << "deflation 4.4 with i = " << i << " because " << diag(i) << " - " << diag(i - 1)
|
||||||
<< " == " << (diag(i) - diag(i - 1)) << " < "
|
<< " == " << (diag(i) - diag(i - 1)) << " < "
|
||||||
<< NumTraits<RealScalar>::epsilon() * /*diag(i)*/ maxDiag << "\n";
|
<< epsilon_strict << "\n";
|
||||||
#endif
|
#endif
|
||||||
eigen_internal_assert(abs(diag(i) - diag(i - 1)) < epsilon_coarse &&
|
eigen_internal_assert(abs(diag(i) - diag(i - 1)) < epsilon_coarse &&
|
||||||
" diagonal entries are not properly sorted");
|
" diagonal entries are not properly sorted");
|
||||||
deflation44(firstCol, firstCol + shift, firstRowW, firstColW, i - 1, i, length);
|
deflation44(firstCol, firstCol + shift, firstRowW, firstColW, i, i - 1, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +77,14 @@ void bdcsvd_verify_assert(const MatrixType& input = MatrixType()) {
|
|||||||
svd_verify_constructor_options_assert<BDCSVD<MatrixType>>(input);
|
svd_verify_constructor_options_assert<BDCSVD<MatrixType>>(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename MatrixType>
|
||||||
|
void bdcsvd_check_convergence(const MatrixType& input) {
|
||||||
|
BDCSVD<MatrixType, Eigen::ComputeThinU | Eigen::ComputeThinV> svd(input);
|
||||||
|
VERIFY(svd.info() == Eigen::Success);
|
||||||
|
MatrixType D = svd.matrixU() * svd.singularValues().asDiagonal() * svd.matrixV().transpose();
|
||||||
|
VERIFY_IS_APPROX(input, D);
|
||||||
|
}
|
||||||
|
|
||||||
EIGEN_DECLARE_TEST(bdcsvd) {
|
EIGEN_DECLARE_TEST(bdcsvd) {
|
||||||
CALL_SUBTEST_1((bdcsvd_verify_assert<Matrix3f>()));
|
CALL_SUBTEST_1((bdcsvd_verify_assert<Matrix3f>()));
|
||||||
CALL_SUBTEST_2((bdcsvd_verify_assert<Matrix4d>()));
|
CALL_SUBTEST_2((bdcsvd_verify_assert<Matrix4d>()));
|
||||||
@ -163,4 +171,7 @@ EIGEN_DECLARE_TEST(bdcsvd) {
|
|||||||
// With total deflation issues before, when it shouldn't be triggered.
|
// With total deflation issues before, when it shouldn't be triggered.
|
||||||
CALL_SUBTEST_47((compare_bdc_jacobi_instance(true, 3)));
|
CALL_SUBTEST_47((compare_bdc_jacobi_instance(true, 3)));
|
||||||
CALL_SUBTEST_48((compare_bdc_jacobi_instance(false, 3)));
|
CALL_SUBTEST_48((compare_bdc_jacobi_instance(false, 3)));
|
||||||
|
|
||||||
|
// Convergence for large constant matrix (https://gitlab.com/libeigen/eigen/-/issues/2491)
|
||||||
|
CALL_SUBTEST_49(bdcsvd_check_convergence<MatrixXf>(MatrixXf::Constant(500, 500, 1)));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user