mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-08-13 20:26:03 +08:00
bug #1695: fix a numerical robustness issue. Computing the secular equation at the middle range without a shift might give a wrong sign.
(grafted from 45e65fbb7791e453f88f959111cff45e0fb7dd6f )
This commit is contained in:
parent
fe8cd812b0
commit
4a242ac43d
@ -769,6 +769,21 @@ void BDCSVD<MatrixType>::computeSingVals(const ArrayRef& col0, const ArrayRef& d
|
||||
Map<ArrayXr> diagShifted(m_workspace.data()+4*n, n);
|
||||
diagShifted = diag - shift;
|
||||
|
||||
if(k!=actual_n-1)
|
||||
{
|
||||
// check that after the shift, f(mid) is still negative:
|
||||
RealScalar midShifted = (right - left) / RealScalar(2);
|
||||
if(shift==right)
|
||||
midShifted = -midShifted;
|
||||
RealScalar fMidShifted = secularEq(midShifted, col0, diag, perm, diagShifted, shift);
|
||||
if(fMidShifted>0)
|
||||
{
|
||||
// fMid was erroneous, fix it:
|
||||
shift = fMidShifted > Literal(0) ? left : right;
|
||||
diagShifted = diag - shift;
|
||||
}
|
||||
}
|
||||
|
||||
// initial guess
|
||||
RealScalar muPrev, muCur;
|
||||
if (shift == left)
|
||||
@ -845,11 +860,13 @@ void BDCSVD<MatrixType>::computeSingVals(const ArrayRef& col0, const ArrayRef& d
|
||||
}
|
||||
|
||||
RealScalar fLeft = secularEq(leftShifted, col0, diag, perm, diagShifted, shift);
|
||||
eigen_internal_assert(fLeft<Literal(0));
|
||||
|
||||
#if defined EIGEN_INTERNAL_DEBUGGING || defined EIGEN_BDCSVD_DEBUG_VERBOSE
|
||||
RealScalar fRight = secularEq(rightShifted, col0, diag, perm, diagShifted, shift);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
||||
if(!(fLeft * fRight<0))
|
||||
{
|
||||
@ -859,10 +876,14 @@ void BDCSVD<MatrixType>::computeSingVals(const ArrayRef& col0, const ArrayRef& d
|
||||
#endif
|
||||
eigen_internal_assert(fLeft * fRight < Literal(0));
|
||||
|
||||
if(fLeft<Literal(0))
|
||||
{
|
||||
while (rightShifted - leftShifted > Literal(2) * NumTraits<RealScalar>::epsilon() * numext::maxi<RealScalar>(abs(leftShifted), abs(rightShifted)))
|
||||
{
|
||||
RealScalar midShifted = (leftShifted + rightShifted) / Literal(2);
|
||||
fMid = secularEq(midShifted, col0, diag, perm, diagShifted, shift);
|
||||
eigen_internal_assert((numext::isfinite)(fMid));
|
||||
|
||||
if (fLeft * fMid < Literal(0))
|
||||
{
|
||||
rightShifted = midShifted;
|
||||
@ -873,9 +894,19 @@ void BDCSVD<MatrixType>::computeSingVals(const ArrayRef& col0, const ArrayRef& d
|
||||
fLeft = fMid;
|
||||
}
|
||||
}
|
||||
|
||||
muCur = (leftShifted + rightShifted) / Literal(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have a problem as shifting on the left or right give either a positive or negative value
|
||||
// at the middle of [left,right]...
|
||||
// Instead fo abbording or entering an infinite loop,
|
||||
// let's just use the middle as the estimated zero-crossing:
|
||||
muCur = (right - left) * RealScalar(0.5);
|
||||
if(shift == right)
|
||||
muCur = -muCur;
|
||||
}
|
||||
}
|
||||
|
||||
singVals[k] = shift + muCur;
|
||||
shifts[k] = shift;
|
||||
@ -924,7 +955,7 @@ void BDCSVD<MatrixType>::perturbCol0
|
||||
Index j = i<k ? i : perm(l-1);
|
||||
prod *= ((singVals(j)+dk) / ((diag(i)+dk))) * ((mus(j)+(shifts(j)-dk)) / ((diag(i)-dk)));
|
||||
#ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
|
||||
if(i!=k && std::abs(((singVals(j)+dk)*(mus(j)+(shifts(j)-dk)))/((diag(i)+dk)*(diag(i)-dk)) - 1) > 0.9 )
|
||||
if(i!=k && numext::abs(((singVals(j)+dk)*(mus(j)+(shifts(j)-dk)))/((diag(i)+dk)*(diag(i)-dk)) - 1) > 0.9 )
|
||||
std::cout << " " << ((singVals(j)+dk)*(mus(j)+(shifts(j)-dk)))/((diag(i)+dk)*(diag(i)-dk)) << " == (" << (singVals(j)+dk) << " * " << (mus(j)+(shifts(j)-dk))
|
||||
<< ") / (" << (diag(i)+dk) << " * " << (diag(i)-dk) << ")\n";
|
||||
#endif
|
||||
@ -934,7 +965,7 @@ void BDCSVD<MatrixType>::perturbCol0
|
||||
std::cout << "zhat(" << k << ") = sqrt( " << prod << ") ; " << (singVals(last) + dk) << " * " << mus(last) + shifts(last) << " - " << dk << "\n";
|
||||
#endif
|
||||
RealScalar tmp = sqrt(prod);
|
||||
zhat(k) = col0(k) > Literal(0) ? tmp : -tmp;
|
||||
zhat(k) = col0(k) > Literal(0) ? RealScalar(tmp) : RealScalar(-tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user