25#include "./InternalHeaderCheck.h"
28#include "BDCSVDImpl.h"
32template <
typename MatrixType_,
int Options>
37template <
typename MatrixType_,
int Options>
38struct traits<BDCSVD<MatrixType_, Options> > : svd_traits<MatrixType_, Options> {
39 using MatrixType = MatrixType_;
75template <
typename MatrixType_,
int Options_>
86 using MatrixType = MatrixType_;
87 using Scalar =
typename Base::Scalar;
88 using RealScalar =
typename Base::RealScalar;
89 using Literal =
typename NumTraits<RealScalar>::Literal;
93 QRDecomposition = internal::get_qr_preconditioner(Options),
94 ComputationOptions = internal::get_computation_options(Options),
95 RowsAtCompileTime = Base::RowsAtCompileTime,
96 ColsAtCompileTime = Base::ColsAtCompileTime,
97 DiagSizeAtCompileTime = Base::DiagSizeAtCompileTime,
98 MaxRowsAtCompileTime = Base::MaxRowsAtCompileTime,
99 MaxColsAtCompileTime = Base::MaxColsAtCompileTime,
100 MaxDiagSizeAtCompileTime = Base::MaxDiagSizeAtCompileTime,
101 MatrixOptions = Base::MatrixOptions
104 using MatrixUType =
typename Base::MatrixUType;
105 using MatrixVType =
typename Base::MatrixVType;
106 using SingularValuesType =
typename Base::SingularValuesType;
121 BDCSVD() : m_isTranspose(false), m_numIters(0) {}
129 BDCSVD(Index rows, Index cols) : m_numIters(0) { allocate(rows, cols, internal::get_computation_options(Options)); }
147 EIGEN_DEPRECATED_WITH_REASON(
"Options should be specified using the class template parameter.")
148 BDCSVD(Index rows, Index cols,
unsigned int computationOptions) : m_numIters(0) {
149 internal::check_svd_options_assertions<MatrixType, Options>(computationOptions, rows, cols);
150 allocate(rows, cols, computationOptions);
158 template <
typename Derived>
160 compute_impl(matrix, internal::get_computation_options(Options));
172 template <
typename DerivedD,
typename DerivedE>
174 compute_bidiagonal_impl(diagonal, superdiagonal, internal::get_computation_options(Options));
189 template <
typename Derived>
190 EIGEN_DEPRECATED_WITH_REASON(
"Options should be specified using the class template parameter.")
191 BDCSVD(const
MatrixBase<Derived>& matrix,
unsigned int computationOptions) : m_numIters(0) {
192 internal::check_svd_options_assertions<MatrixType, Options>(computationOptions, matrix.rows(), matrix.cols());
193 compute_impl(matrix, computationOptions);
201 template <
typename Derived>
203 return compute_impl(matrix, m_computationOptions);
215 template <
typename Derived>
216 EIGEN_DEPRECATED_WITH_REASON(
"Options should be specified using the class template parameter.")
218 internal::check_svd_options_assertions<MatrixType, Options>(computationOptions, matrix.rows(), matrix.cols());
219 return compute_impl(matrix, computationOptions);
231 template <
typename DerivedD,
typename DerivedE>
233 return compute_bidiagonal_impl(diagonal, superdiagonal, m_computationOptions);
236 void setSwitchSize(
int s) {
237 eigen_assert(s >= 3 &&
"BDCSVD the size of the algo switch has to be at least 3.");
238 if (s == m_impl.algoSwap())
return;
239 m_impl.setAlgoSwap(s);
241 m_isAllocated =
false;
245 template <
typename Derived>
246 BDCSVD& compute_impl(
const MatrixBase<Derived>& matrix,
unsigned int computationOptions);
247 template <
typename Derived>
248 BDCSVD& compute_impl(
const MatrixBase<Derived>& matrix,
unsigned int computationOptions, internal::true_type);
249 template <
typename Derived>
250 BDCSVD& compute_impl(
const MatrixBase<Derived>& matrix,
unsigned int computationOptions, internal::false_type);
251 template <
typename DerivedD,
typename DerivedE>
252 BDCSVD& compute_bidiagonal_impl(
const MatrixBase<DerivedD>& diagonal,
const MatrixBase<DerivedE>& superdiagonal,
253 unsigned int computationOptions);
254 template <
typename HouseholderU,
typename HouseholderV,
typename NaiveU,
typename NaiveV>
255 void copyUV(
const HouseholderU& householderU,
const HouseholderV& householderV,
const NaiveU& naiveU,
256 const NaiveV& naivev);
259 void allocate(Index rows, Index cols,
unsigned int computationOptions);
260 void allocate_small(Index rows, Index cols,
unsigned int computationOptions);
261 internal::bdcsvd_impl<RealScalar> m_impl;
262 bool m_isTranspose, m_useQrDecomp;
266 HouseholderQR<MatrixX> qrDecomp;
267 internal::UpperBidiagonalization<MatrixX> bid;
268 MatrixX copyWorkspace;
269 MatrixX reducedTriangle;
272 Matrix<Scalar, 1, Dynamic, RowMajor> m_householderWorkspace;
274 using Base::m_computationOptions;
275 using Base::m_computeThinU;
276 using Base::m_computeThinV;
278 using Base::m_isAllocated;
279 using Base::m_isInitialized;
280 using Base::m_matrixU;
281 using Base::m_matrixV;
282 using Base::m_nonzeroSingularValues;
283 using Base::m_singularValues;
290template <
typename MatrixType,
int Options>
291void BDCSVD<MatrixType, Options>::allocate(Index rows, Index cols,
unsigned int computationOptions) {
292 if (Base::allocate(rows, cols, computationOptions))
return;
294 if (cols < m_impl.algoSwap())
295 smallSvd.allocate(rows, cols, internal::get_computation_options(Options | computationOptions));
297 m_isTranspose = (cols > rows);
299 bool compU = computeV();
300 bool compV = computeU();
301 if (m_isTranspose) std::swap(compU, compV);
303 m_impl.allocate(diagSize(), compU, compV);
309 constexpr Index kMinAspectRatio = 4;
310 constexpr bool disableQrDecomp =
static_cast<int>(QRDecomposition) ==
static_cast<int>(
DisableQRDecomposition);
311 m_useQrDecomp = !disableQrDecomp && ((rows / kMinAspectRatio >= cols) || (cols / kMinAspectRatio >= rows));
314 reducedTriangle =
MatrixX(diagSize(), diagSize());
317 copyWorkspace =
MatrixX(m_isTranspose ? cols : rows, m_isTranspose ? rows : cols);
318 bid = internal::UpperBidiagonalization<MatrixX>(m_useQrDecomp ? diagSize() : copyWorkspace.rows(),
319 m_useQrDecomp ? diagSize() : copyWorkspace.cols());
322template <
typename MatrixType,
int Options>
323void BDCSVD<MatrixType, Options>::allocate_small(Index rows, Index cols,
unsigned int computationOptions) {
324 if (Base::allocate(rows, cols, computationOptions))
return;
326 smallSvd.allocate(rows, cols, internal::get_computation_options(Options | computationOptions));
327 m_isTranspose = (cols > rows);
330template <
typename MatrixType,
int Options>
331template <
typename Derived>
333 unsigned int computationOptions) {
334 EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived, MatrixType);
335 EIGEN_STATIC_ASSERT((std::is_same<typename Derived::Scalar, typename MatrixType::Scalar>::value),
336 Input matrix must have the same Scalar type as the
BDCSVD object.);
339 typedef internal::bool_constant<(MaxColsAtCompileTime != Dynamic && MaxColsAtCompileTime < 3)> AlwaysUseSmallSvd;
340 return compute_impl(matrix, computationOptions, AlwaysUseSmallSvd());
343template <
typename MatrixType,
int Options>
344template <
typename Derived>
347 allocate_small(matrix.rows(), matrix.cols(), computationOptions);
349 smallSvd.compute(matrix);
350 m_isInitialized =
true;
351 m_info = smallSvd.info();
353 if (computeU()) m_matrixU = smallSvd.matrixU();
354 if (computeV()) m_matrixV = smallSvd.matrixV();
355 m_singularValues = smallSvd.singularValues();
356 m_nonzeroSingularValues = smallSvd.nonzeroSingularValues();
361template <
typename MatrixType,
int Options>
362template <
typename Derived>
364 const MatrixBase<Derived>& matrix,
unsigned int computationOptions, internal::false_type) {
367 allocate(matrix.rows(), matrix.cols(), computationOptions);
369 const RealScalar considerZero = (std::numeric_limits<RealScalar>::min)();
372 if (matrix.cols() < m_impl.algoSwap()) {
373 smallSvd.compute(matrix);
374 m_isInitialized =
true;
375 m_info = smallSvd.info();
377 if (computeU()) m_matrixU = smallSvd.matrixU();
378 if (computeV()) m_matrixV = smallSvd.matrixV();
379 m_singularValues = smallSvd.singularValues();
380 m_nonzeroSingularValues = smallSvd.nonzeroSingularValues();
388 const RealScalar maxCoeff = internal::safe_scaling<RealScalar>::recover_flushed_max_coeff(
389 matrix.derived(), matrix.cwiseAbs().template maxCoeff<PropagateNaN>());
390 if (!(numext::isfinite)(maxCoeff)) {
391 m_isInitialized =
true;
396 const auto factors = m_isTranspose
397 ? internal::safe_scaling<RealScalar>::scale_to(copyWorkspace, matrix.adjoint(), maxCoeff)
398 : internal::safe_scaling<RealScalar>::scale_to(copyWorkspace, matrix, maxCoeff);
405 qrDecomp.compute(copyWorkspace);
406 reducedTriangle = qrDecomp.matrixQR().topRows(diagSize());
407 reducedTriangle.template triangularView<StrictlyLower>().setZero();
408 bid.compute(reducedTriangle);
410 bid.compute(copyWorkspace);
414 m_impl.naiveU().setZero();
415 m_impl.naiveV().setZero();
421 m_impl.computed().setZero();
422 m_impl.computed().topRows(diagSize()).diagonal() = bid.bidiagonal().diagonal();
423 m_impl.computed().topRows(diagSize()).
template diagonal<-1>() = bid.bidiagonal().diagonal(1);
424 m_impl.splitNegligibleSuperdiagonal(diagSize());
425 m_impl.divide(0, diagSize() - 1, 0, 0, 0);
426 m_info = m_impl.info();
427 m_numIters = m_impl.numIters();
429 m_isInitialized =
true;
434 for (
int i = 0; i < diagSize(); i++) {
435 RealScalar a = abs(m_impl.computed().coeff(i, i));
436 m_singularValues.coeffRef(i) = a;
437 if (a < considerZero) {
438 m_nonzeroSingularValues = i;
439 m_singularValues.tail(diagSize() - i - 1).setZero();
441 }
else if (i == diagSize() - 1) {
442 m_nonzeroSingularValues = i + 1;
447 internal::safe_scaling<RealScalar>::unscale_in_place(m_singularValues, maxCoeff, factors);
451 copyUV(bid.householderV(), bid.householderU(), m_impl.naiveV(), m_impl.naiveU());
453 copyUV(bid.householderU(), bid.householderV(), m_impl.naiveU(), m_impl.naiveV());
456 if (m_isTranspose && computeV())
457 m_matrixV.applyOnTheLeft(qrDecomp.householderQ());
458 else if (!m_isTranspose && computeU())
459 m_matrixU.applyOnTheLeft(qrDecomp.householderQ());
462 m_isInitialized =
true;
466template <
typename MatrixType,
int Options>
467template <
typename HouseholderU,
typename HouseholderV,
typename NaiveU,
typename NaiveV>
468EIGEN_DONT_INLINE
void BDCSVD<MatrixType, Options>::copyUV(
const HouseholderU& householderU,
469 const HouseholderV& householderV,
const NaiveU& naiveU,
470 const NaiveV& naiveV) {
476 Index Ucols = m_computeThinU ? diagSize() : rows();
477 m_matrixU = MatrixX::Identity(rows(), Ucols);
478 m_matrixU.topLeftCorner(diagSize(), diagSize()) =
479 naiveV.topLeftCorner(diagSize(), diagSize()).template cast<Scalar>();
481 auto sub = m_matrixU.topLeftCorner(householderU.cols(), diagSize());
482 householderU.applyThisOnTheLeft(sub, m_householderWorkspace);
484 householderU.applyThisOnTheLeft(m_matrixU, m_householderWorkspace);
488 Index Vcols = m_computeThinV ? diagSize() : cols();
489 m_matrixV = MatrixX::Identity(cols(), Vcols);
490 m_matrixV.topLeftCorner(diagSize(), diagSize()) =
491 naiveU.topLeftCorner(diagSize(), diagSize()).template cast<Scalar>();
493 auto sub = m_matrixV.topLeftCorner(householderV.cols(), diagSize());
494 householderV.applyThisOnTheLeft(sub, m_householderWorkspace);
496 householderV.applyThisOnTheLeft(m_matrixV, m_householderWorkspace);
501template <
typename MatrixType,
int Options>
502template <
typename DerivedD,
typename DerivedE>
505 EIGEN_STATIC_ASSERT(DerivedD::IsVectorAtCompileTime, THIS_METHOD_IS_ONLY_FOR_VECTORS);
506 EIGEN_STATIC_ASSERT(DerivedE::IsVectorAtCompileTime, THIS_METHOD_IS_ONLY_FOR_VECTORS);
507 EIGEN_STATIC_ASSERT((NumTraits<typename DerivedD::Scalar>::IsComplex == 0),
508 THIS_FUNCTION_IS_NOT_FOR_COMPLEX_VALUED_MATRICES);
509 EIGEN_STATIC_ASSERT((NumTraits<typename DerivedE::Scalar>::IsComplex == 0),
510 THIS_FUNCTION_IS_NOT_FOR_COMPLEX_VALUED_MATRICES);
513 const Index n = diagonal.size();
514 eigen_assert((n == 0 || superdiagonal.size() == n - 1) &&
"superdiagonal must have size diagonal.size() - 1");
517 allocate(n, n, computationOptions);
520 m_isInitialized =
true;
522 m_nonzeroSingularValues = 0;
527 const RealScalar diagScale = internal::safe_scaling<RealScalar>::recover_flushed_max_coeff(
528 diagonal.derived(), diagonal.cwiseAbs().template maxCoeff<PropagateNaN>());
529 const RealScalar superdiagScale =
530 n > 1 ? internal::safe_scaling<RealScalar>::recover_flushed_max_coeff(
531 superdiagonal.derived(), superdiagonal.cwiseAbs().template maxCoeff<PropagateNaN>())
533 const RealScalar maxCoeff = internal::max_preserving_subnormals(diagScale, superdiagScale);
534 if (!(numext::isfinite)(maxCoeff)) {
535 m_isInitialized =
true;
540 const RealScalar considerZero = (std::numeric_limits<RealScalar>::min)();
542 if (n < m_impl.algoSwap()) {
544 MatrixX B = MatrixX::Zero(n, n);
545 auto diagonalDest = B.diagonal();
547 internal::safe_scaling<RealScalar>::scale_to(diagonalDest, diagonal.template cast<Scalar>(), maxCoeff);
549 auto superdiagonalDest = B.diagonal(1);
550 internal::safe_scaling<RealScalar>::scale_to(superdiagonalDest, superdiagonal.template cast<Scalar>(), maxCoeff,
554 m_isInitialized =
true;
555 m_info = smallSvd.info();
557 internal::safe_scaling<RealScalar>::unscale_to(m_singularValues, smallSvd.singularValues(), maxCoeff, factors);
558 m_nonzeroSingularValues = smallSvd.nonzeroSingularValues();
559 if (computeU()) m_matrixU = smallSvd.matrixU();
560 if (computeV()) m_matrixV = smallSvd.matrixV();
567 m_impl.naiveU().setZero();
568 m_impl.naiveV().setZero();
569 m_impl.computed().setZero();
570 auto diagonalDest = m_impl.computed().diagonal();
572 internal::safe_scaling<RealScalar>::scale_to(diagonalDest, diagonal.template cast<RealScalar>(), maxCoeff);
574 auto superdiagonalDest = m_impl.computed().template diagonal<-1>().head(n - 1);
575 internal::safe_scaling<RealScalar>::scale_to(superdiagonalDest, superdiagonal.template cast<RealScalar>(), maxCoeff,
579 m_isTranspose =
false;
582 m_impl.splitNegligibleSuperdiagonal(n);
583 m_impl.divide(0, n - 1, 0, 0, 0);
584 m_info = m_impl.info();
585 m_numIters = m_impl.numIters();
587 m_isInitialized =
true;
592 for (
int i = 0; i < diagSize(); i++) {
593 RealScalar a = abs(m_impl.computed().coeff(i, i));
594 m_singularValues.coeffRef(i) = a;
595 if (a < considerZero) {
596 m_nonzeroSingularValues = i;
597 m_singularValues.tail(diagSize() - i - 1).setZero();
599 }
else if (i == diagSize() - 1) {
600 m_nonzeroSingularValues = i + 1;
605 internal::safe_scaling<RealScalar>::unscale_in_place(m_singularValues, maxCoeff, factors);
611 Index Ucols = m_computeThinU ? diagSize() : rows();
612 m_matrixU = MatrixX::Identity(rows(), Ucols);
613 m_matrixU.topLeftCorner(diagSize(), diagSize()) =
614 m_impl.naiveV().template cast<Scalar>().topLeftCorner(diagSize(), diagSize());
617 Index Vcols = m_computeThinV ? diagSize() : cols();
618 m_matrixV = MatrixX::Identity(cols(), Vcols);
619 m_matrixV.topLeftCorner(diagSize(), diagSize()) =
620 m_impl.naiveU().template cast<Scalar>().topLeftCorner(diagSize(), diagSize());
623 m_isInitialized =
true;
633template <
typename Derived>
634template <
int Options>
645template <
typename Derived>
646template <
int Options>
648 unsigned int computationOptions)
const {
General-purpose arrays with easy API for coefficient-wise operations.
Definition Array.h:55
class Bidiagonal Divide and Conquer SVD
Definition BDCSVD.h:76
BDCSVD(const MatrixBase< DerivedD > &diagonal, const MatrixBase< DerivedE > &superdiagonal)
Constructor performing the SVD of an upper bidiagonal matrix given its diagonal and superdiagonal.
Definition BDCSVD.h:173
BDCSVD()
Default Constructor.
Definition BDCSVD.h:121
BDCSVD(const MatrixBase< Derived > &matrix)
Constructor performing the decomposition of given matrix, using the custom options specified with the...
Definition BDCSVD.h:159
BDCSVD & compute(const MatrixBase< Derived > &matrix)
Method performing the decomposition of given matrix. Computes Thin/Full unitaries U/V if specified us...
Definition BDCSVD.h:202
BDCSVD & compute(const MatrixBase< DerivedD > &diagonal, const MatrixBase< DerivedE > &superdiagonal)
Compute the SVD of an upper bidiagonal matrix given its diagonal and superdiagonal.
Definition BDCSVD.h:232
BDCSVD(Index rows, Index cols)
Default Constructor with memory preallocation.
Definition BDCSVD.h:129
Householder QR decomposition of a matrix.
Definition HouseholderQR.h:77
Base class for all dense matrices, vectors, and expressions.
Definition MatrixBase.h:53
The matrix class, also used for vectors and row-vectors.
Definition Matrix.h:188
A matrix or vector expression mapping an existing expression.
Definition Ref.h:262
bool computeV() const
Definition SVDBase.h:278
bool computeU() const
Definition SVDBase.h:276
SVDBase()
Definition SVDBase.h:352
@ DisableQRDecomposition
Definition Constants.h:434
@ PreconditionSquareMatrix
Definition Constants.h:437
@ InvalidInput
Definition Constants.h:464
@ Success
Definition Constants.h:457
@ NoConvergence
Definition Constants.h:461
Matrix< Type, Dynamic, Dynamic > MatrixX
Dynamic×Dynamic matrix of type Type.
Definition Matrix.h:524
Eigen::Index Index
The interface type of indices.
Definition EigenBase.h:44