mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-01-30 17:40:05 +08:00
Merged latest updates from trunk
This commit is contained in:
commit
00dfe18487
@ -350,7 +350,8 @@ template<typename MatrixType, int QRPreconditioner>
|
||||
struct svd_precondition_2x2_block_to_be_real<MatrixType, QRPreconditioner, false>
|
||||
{
|
||||
typedef JacobiSVD<MatrixType, QRPreconditioner> SVD;
|
||||
static bool run(typename SVD::WorkMatrixType&, SVD&, Index, Index, const typename MatrixType::RealScalar&) { return true; }
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
static bool run(typename SVD::WorkMatrixType&, SVD&, Index, Index, RealScalar&) { return true; }
|
||||
};
|
||||
|
||||
template<typename MatrixType, int QRPreconditioner>
|
||||
@ -359,25 +360,30 @@ struct svd_precondition_2x2_block_to_be_real<MatrixType, QRPreconditioner, true>
|
||||
typedef JacobiSVD<MatrixType, QRPreconditioner> SVD;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
static bool run(typename SVD::WorkMatrixType& work_matrix, SVD& svd, Index p, Index q, const typename MatrixType::RealScalar& precision)
|
||||
static bool run(typename SVD::WorkMatrixType& work_matrix, SVD& svd, Index p, Index q, RealScalar& maxDiagEntry)
|
||||
{
|
||||
using std::sqrt;
|
||||
using std::abs;
|
||||
Scalar z;
|
||||
JacobiRotation<Scalar> rot;
|
||||
RealScalar n = sqrt(numext::abs2(work_matrix.coeff(p,p)) + numext::abs2(work_matrix.coeff(q,p)));
|
||||
|
||||
|
||||
const RealScalar considerAsZero = (std::numeric_limits<RealScalar>::min)();
|
||||
const RealScalar precision = NumTraits<Scalar>::epsilon();
|
||||
|
||||
if(n==0)
|
||||
{
|
||||
// make sure first column is zero
|
||||
work_matrix.coeffRef(p,p) = work_matrix.coeffRef(q,p) = Scalar(0);
|
||||
if(work_matrix.coeff(p,q)!=Scalar(0))
|
||||
|
||||
if(abs(numext::imag(work_matrix.coeff(p,q)))>considerAsZero)
|
||||
{
|
||||
// work_matrix.coeff(p,q) can be zero if work_matrix.coeff(q,p) is not zero but small enough to underflow when computing n
|
||||
z = abs(work_matrix.coeff(p,q)) / work_matrix.coeff(p,q);
|
||||
work_matrix.row(p) *= z;
|
||||
if(svd.computeU()) svd.m_matrixU.col(p) *= conj(z);
|
||||
}
|
||||
if(work_matrix.coeff(q,q)!=Scalar(0))
|
||||
if(abs(numext::imag(work_matrix.coeff(q,q)))>considerAsZero)
|
||||
{
|
||||
z = abs(work_matrix.coeff(q,q)) / work_matrix.coeff(q,q);
|
||||
work_matrix.row(q) *= z;
|
||||
@ -391,13 +397,13 @@ struct svd_precondition_2x2_block_to_be_real<MatrixType, QRPreconditioner, true>
|
||||
rot.s() = work_matrix.coeff(q,p) / n;
|
||||
work_matrix.applyOnTheLeft(p,q,rot);
|
||||
if(svd.computeU()) svd.m_matrixU.applyOnTheRight(p,q,rot.adjoint());
|
||||
if(work_matrix.coeff(p,q) != Scalar(0))
|
||||
if(abs(numext::imag(work_matrix.coeff(p,q)))>considerAsZero)
|
||||
{
|
||||
z = abs(work_matrix.coeff(p,q)) / work_matrix.coeff(p,q);
|
||||
work_matrix.col(q) *= z;
|
||||
if(svd.computeV()) svd.m_matrixV.col(q) *= z;
|
||||
}
|
||||
if(work_matrix.coeff(q,q) != Scalar(0))
|
||||
if(abs(numext::imag(work_matrix.coeff(q,q)))>considerAsZero)
|
||||
{
|
||||
z = abs(work_matrix.coeff(q,q)) / work_matrix.coeff(q,q);
|
||||
work_matrix.row(q) *= z;
|
||||
@ -405,11 +411,11 @@ struct svd_precondition_2x2_block_to_be_real<MatrixType, QRPreconditioner, true>
|
||||
}
|
||||
}
|
||||
|
||||
const RealScalar considerAsZero = RealScalar(2) * std::numeric_limits<RealScalar>::denorm_min();
|
||||
RealScalar threshold = numext::maxi<RealScalar>(considerAsZero,
|
||||
precision * numext::maxi<RealScalar>(abs(work_matrix.coeff(p,p)), abs(work_matrix.coeff(q,q))));
|
||||
// return true if we still have some work to do
|
||||
return numext::abs(work_matrix(p,q)) > threshold || numext::abs(work_matrix(q,p)) > threshold;
|
||||
// update largest diagonal entry
|
||||
maxDiagEntry = numext::maxi(maxDiagEntry,numext::maxi(abs(work_matrix.coeff(p,p)), abs(work_matrix.coeff(q,q))));
|
||||
// and check whether the 2x2 block is already diagonal
|
||||
RealScalar threshold = numext::maxi<RealScalar>(considerAsZero, precision * maxDiagEntry);
|
||||
return abs(work_matrix.coeff(p,q))>threshold || abs(work_matrix.coeff(q,p)) > threshold;
|
||||
}
|
||||
};
|
||||
|
||||
@ -426,7 +432,6 @@ void real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q,
|
||||
JacobiRotation<RealScalar> rot1;
|
||||
RealScalar t = m.coeff(0,0) + m.coeff(1,1);
|
||||
RealScalar d = m.coeff(1,0) - m.coeff(0,1);
|
||||
|
||||
if(d == RealScalar(0))
|
||||
{
|
||||
rot1.s() = RealScalar(0);
|
||||
@ -719,6 +724,7 @@ JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsig
|
||||
}
|
||||
|
||||
/*** step 2. The main Jacobi SVD iteration. ***/
|
||||
RealScalar maxDiagEntry = m_workMatrix.cwiseAbs().diagonal().maxCoeff();
|
||||
|
||||
bool finished = false;
|
||||
while(!finished)
|
||||
@ -734,16 +740,13 @@ JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsig
|
||||
// if this 2x2 sub-matrix is not diagonal already...
|
||||
// notice that this comparison will evaluate to false if any NaN is involved, ensuring that NaN's don't
|
||||
// keep us iterating forever. Similarly, small denormal numbers are considered zero.
|
||||
RealScalar threshold = numext::maxi<RealScalar>(considerAsZero,
|
||||
precision * numext::maxi<RealScalar>(abs(m_workMatrix.coeff(p,p)),
|
||||
abs(m_workMatrix.coeff(q,q))));
|
||||
// We compare both values to threshold instead of calling max to be robust to NaN (See bug 791)
|
||||
RealScalar threshold = numext::maxi<RealScalar>(considerAsZero, precision * maxDiagEntry);
|
||||
if(abs(m_workMatrix.coeff(p,q))>threshold || abs(m_workMatrix.coeff(q,p)) > threshold)
|
||||
{
|
||||
finished = false;
|
||||
// perform SVD decomposition of 2x2 sub-matrix corresponding to indices p,q to make it diagonal
|
||||
// the complex to real operation returns true is the updated 2x2 block is not already diagonal
|
||||
if(internal::svd_precondition_2x2_block_to_be_real<MatrixType, QRPreconditioner>::run(m_workMatrix, *this, p, q, precision))
|
||||
if(internal::svd_precondition_2x2_block_to_be_real<MatrixType, QRPreconditioner>::run(m_workMatrix, *this, p, q, maxDiagEntry))
|
||||
{
|
||||
JacobiRotation<RealScalar> j_left, j_right;
|
||||
internal::real_2x2_jacobi_svd(m_workMatrix, p, q, &j_left, &j_right);
|
||||
@ -754,6 +757,9 @@ JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsig
|
||||
|
||||
m_workMatrix.applyOnTheRight(p,q,j_right);
|
||||
if(computeV()) m_matrixV.applyOnTheRight(p,q,j_right);
|
||||
|
||||
// keep track of the largest diagonal coefficient
|
||||
maxDiagEntry = numext::maxi(maxDiagEntry,numext::maxi(abs(m_workMatrix.coeff(p,p)), abs(m_workMatrix.coeff(q,q))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,6 +80,8 @@ void svd_fill_random(MatrixType &m, int Option = 0)
|
||||
Index i = internal::random<Index>(0,m.rows()-1);
|
||||
Index j = internal::random<Index>(0,m.cols()-1);
|
||||
m(j,i) = m(i,j) = samples(internal::random<Index>(0,samples.size()-1));
|
||||
if(NumTraits<Scalar>::IsComplex)
|
||||
*(&numext::real_ref(m(j,i))+1) = *(&numext::real_ref(m(i,j))+1) = samples.real()(internal::random<Index>(0,samples.size()-1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -91,8 +93,14 @@ void svd_fill_random(MatrixType &m, int Option = 0)
|
||||
if(!(dup && unit_uv))
|
||||
{
|
||||
Index n = internal::random<Index>(0,m.size()-1);
|
||||
for(Index i=0; i<n; ++i)
|
||||
m(internal::random<Index>(0,m.rows()-1), internal::random<Index>(0,m.cols()-1)) = samples(internal::random<Index>(0,samples.size()-1));
|
||||
for(Index k=0; k<n; ++k)
|
||||
{
|
||||
Index i = internal::random<Index>(0,m.rows()-1);
|
||||
Index j = internal::random<Index>(0,m.cols()-1);
|
||||
m(i,j) = samples(internal::random<Index>(0,samples.size()-1));
|
||||
if(NumTraits<Scalar>::IsComplex)
|
||||
*(&numext::real_ref(m(i,j))+1) = samples.real()(internal::random<Index>(0,samples.size()-1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user