aboutsummaryrefslogtreecommitdiffhomepage
path: root/Eigen/src/SVD
diff options
context:
space:
mode:
authorGravatar Benoit Jacob <jacob.benoit.1@gmail.com>2009-08-12 18:23:39 -0400
committerGravatar Benoit Jacob <jacob.benoit.1@gmail.com>2009-08-12 18:23:39 -0400
commit2b618a2c1631548b00af3fe923e9db76aca71825 (patch)
tree6cbe9347e5ba541c0f22346e376f96e1e2fce612 /Eigen/src/SVD
parent309d540d4a71527a4dba778dc5221b81fd18f540 (diff)
make jacobi SVD more robust after experimenting with very nasty matrices...
it turns out to be better to repeat the jacobi steps on a given (p,q) pair until it is diagonal to machine precision, before going to the next (p,q) pair. it's also an optimization as experiments show that in a majority of cases this allows to find out that the (p,q) pair is already diagonal to machine precision.
Diffstat (limited to 'Eigen/src/SVD')
-rw-r--r--Eigen/src/SVD/JacobiSquareSVD.h41
1 files changed, 25 insertions, 16 deletions
diff --git a/Eigen/src/SVD/JacobiSquareSVD.h b/Eigen/src/SVD/JacobiSquareSVD.h
index 18416e312..18c3db980 100644
--- a/Eigen/src/SVD/JacobiSquareSVD.h
+++ b/Eigen/src/SVD/JacobiSquareSVD.h
@@ -102,14 +102,16 @@ void JacobiSquareSVD<MatrixType, ComputeU, ComputeV>::compute(const MatrixType&
if(ComputeU) m_matrixU = MatrixUType::Identity(size,size);
if(ComputeV) m_matrixV = MatrixUType::Identity(size,size);
m_singularValues.resize(size);
- while(true)
+
+sweep_again:
+ for(int p = 1; p < size; ++p)
{
- bool finished = true;
- for(int p = 1; p < size; ++p)
+ for(int q = 0; q < p; ++q)
{
- for(int q = 0; q < p; ++q)
- {
- Scalar c, s;
+ Scalar c, s;
+ while(std::max(ei_abs(work_matrix.coeff(p,q)),ei_abs(work_matrix.coeff(q,p)))
+ > std::max(ei_abs(work_matrix.coeff(p,p)),ei_abs(work_matrix.coeff(q,q)))*machine_epsilon<Scalar>())
+ {
if(work_matrix.makeJacobiForAtA(p,q,&c,&s))
{
work_matrix.applyJacobiOnTheRight(p,q,c,s);
@@ -117,9 +119,13 @@ void JacobiSquareSVD<MatrixType, ComputeU, ComputeV>::compute(const MatrixType&
}
if(work_matrix.makeJacobiForAAt(p,q,&c,&s))
{
+ Scalar x = ei_abs2(work_matrix.coeff(p,p)) + ei_abs2(work_matrix.coeff(p,q));
+ Scalar y = ei_conj(work_matrix.coeff(q,p))*work_matrix.coeff(p,p) + ei_conj(work_matrix.coeff(q,q))*work_matrix.coeff(p,q);
+ Scalar z = ei_abs2(work_matrix.coeff(q,p)) + ei_abs2(work_matrix.coeff(q,q));
work_matrix.applyJacobiOnTheLeft(p,q,c,s);
if(ComputeU) m_matrixU.applyJacobiOnTheRight(p,q,c,s);
- if(std::max(ei_abs(work_matrix.coeff(p,q)), ei_abs(work_matrix.coeff(q,p))) > std::max(ei_abs(work_matrix.coeff(q,q)), ei_abs(work_matrix.coeff(p,p)) ))
+ if(std::max(ei_abs(work_matrix.coeff(p,q)),ei_abs(work_matrix.coeff(q,p)))
+ > std::max(ei_abs(work_matrix.coeff(p,p)),ei_abs(work_matrix.coeff(q,q))) )
{
work_matrix.row(p).swap(work_matrix.row(q));
if(ComputeU) m_matrixU.col(p).swap(m_matrixU.col(q));
@@ -127,15 +133,18 @@ void JacobiSquareSVD<MatrixType, ComputeU, ComputeV>::compute(const MatrixType&
}
}
}
- RealScalar biggest = work_matrix.diagonal().cwise().abs().maxCoeff();
- for(int p = 0; p < size; ++p)
- {
- for(int q = 0; q < size; ++q)
- {
- if(p!=q && ei_abs(work_matrix.coeff(p,q)) > biggest * machine_epsilon<Scalar>()) finished = false;
- }
- }
- if(finished) break;
+ }
+
+ RealScalar biggestOnDiag = work_matrix.diagonal().cwise().abs().maxCoeff();
+ RealScalar maxAllowedOffDiag = biggestOnDiag * machine_epsilon<Scalar>();
+ for(int p = 0; p < size; ++p)
+ {
+ for(int q = 0; q < p; ++q)
+ if(ei_abs(work_matrix.coeff(p,q)) > maxAllowedOffDiag)
+ goto sweep_again;
+ for(int q = p+1; q < size; ++q)
+ if(ei_abs(work_matrix.coeff(p,q)) > maxAllowedOffDiag)
+ goto sweep_again;
}
m_singularValues = work_matrix.diagonal().cwise().abs();