11 #ifndef EIGEN_JACOBISVD_H 12 #define EIGEN_JACOBISVD_H 19 template<
typename MatrixType,
int QRPreconditioner,
20 bool IsComplex = NumTraits<typename MatrixType::Scalar>::IsComplex>
30 enum { PreconditionIfMoreColsThanRows, PreconditionIfMoreRowsThanCols };
32 template<
typename MatrixType,
int QRPreconditioner,
int Case>
35 enum { a = MatrixType::RowsAtCompileTime !=
Dynamic &&
36 MatrixType::ColsAtCompileTime !=
Dynamic &&
37 MatrixType::ColsAtCompileTime <= MatrixType::RowsAtCompileTime,
38 b = MatrixType::RowsAtCompileTime !=
Dynamic &&
39 MatrixType::ColsAtCompileTime !=
Dynamic &&
40 MatrixType::RowsAtCompileTime <= MatrixType::ColsAtCompileTime,
42 (Case == PreconditionIfMoreColsThanRows &&
bool(a)) ||
43 (Case == PreconditionIfMoreRowsThanCols &&
bool(b)) )
47 template<
typename MatrixType,
int QRPreconditioner,
int Case,
51 template<
typename MatrixType,
int QRPreconditioner,
int Case>
64 template<
typename MatrixType>
68 typedef typename MatrixType::Scalar Scalar;
71 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
72 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime
78 if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols())
81 ::new (&m_qr)
QRType(svd.rows(), svd.cols());
83 if (svd.m_computeFullU) m_workspace.resize(svd.rows());
88 if(matrix.rows() > matrix.cols())
91 svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).
template triangularView<Upper>();
92 if(svd.m_computeFullU) m_qr.matrixQ().evalTo(svd.m_matrixU, m_workspace);
93 if(svd.
computeV()) svd.m_matrixV = m_qr.colsPermutation();
101 WorkspaceType m_workspace;
104 template<
typename MatrixType>
108 typedef typename MatrixType::Scalar Scalar;
111 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
112 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
113 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
114 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
115 Options = MatrixType::Options
122 if (svd.cols() != m_qr.rows() || svd.rows() != m_qr.cols())
125 ::new (&m_qr)
QRType(svd.cols(), svd.rows());
127 m_adjoint.resize(svd.cols(), svd.rows());
128 if (svd.m_computeFullV) m_workspace.resize(svd.cols());
133 if(matrix.cols() > matrix.rows())
135 m_adjoint = matrix.adjoint();
136 m_qr.compute(m_adjoint);
137 svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).
template triangularView<Upper>().adjoint();
138 if(svd.m_computeFullV) m_qr.matrixQ().evalTo(svd.m_matrixV, m_workspace);
139 if(svd.
computeU()) svd.m_matrixU = m_qr.colsPermutation();
147 TransposeTypeWithSameStorageOrder m_adjoint;
153 template<
typename MatrixType>
159 if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols())
162 ::new (&m_qr)
QRType(svd.rows(), svd.cols());
164 if (svd.m_computeFullU) m_workspace.resize(svd.rows());
165 else if (svd.m_computeThinU) m_workspace.resize(svd.cols());
170 if(matrix.rows() > matrix.cols())
172 m_qr.compute(matrix);
173 svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).
template triangularView<Upper>();
174 if(svd.m_computeFullU) m_qr.householderQ().evalTo(svd.m_matrixU, m_workspace);
175 else if(svd.m_computeThinU)
177 svd.m_matrixU.setIdentity(matrix.rows(), matrix.cols());
178 m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixU, m_workspace);
180 if(svd.
computeV()) svd.m_matrixV = m_qr.colsPermutation();
192 template<
typename MatrixType>
196 typedef typename MatrixType::Scalar Scalar;
199 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
200 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
201 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
202 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
203 Options = MatrixType::Options
211 if (svd.cols() != m_qr.rows() || svd.rows() != m_qr.cols())
214 ::new (&m_qr)
QRType(svd.cols(), svd.rows());
216 if (svd.m_computeFullV) m_workspace.resize(svd.cols());
217 else if (svd.m_computeThinV) m_workspace.resize(svd.rows());
218 m_adjoint.resize(svd.cols(), svd.rows());
223 if(matrix.cols() > matrix.rows())
225 m_adjoint = matrix.adjoint();
226 m_qr.compute(m_adjoint);
228 svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).
template triangularView<Upper>().adjoint();
229 if(svd.m_computeFullV) m_qr.householderQ().evalTo(svd.m_matrixV, m_workspace);
230 else if(svd.m_computeThinV)
232 svd.m_matrixV.setIdentity(matrix.cols(), matrix.rows());
233 m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixV, m_workspace);
235 if(svd.
computeU()) svd.m_matrixU = m_qr.colsPermutation();
244 TransposeTypeWithSameStorageOrder m_adjoint;
250 template<
typename MatrixType>
256 if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols())
259 ::new (&m_qr)
QRType(svd.rows(), svd.cols());
261 if (svd.m_computeFullU) m_workspace.resize(svd.rows());
262 else if (svd.m_computeThinU) m_workspace.resize(svd.cols());
267 if(matrix.rows() > matrix.cols())
269 m_qr.compute(matrix);
270 svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).
template triangularView<Upper>();
271 if(svd.m_computeFullU) m_qr.householderQ().evalTo(svd.m_matrixU, m_workspace);
272 else if(svd.m_computeThinU)
274 svd.m_matrixU.setIdentity(matrix.rows(), matrix.cols());
275 m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixU, m_workspace);
277 if(svd.
computeV()) svd.m_matrixV.setIdentity(matrix.cols(), matrix.cols());
288 template<
typename MatrixType>
292 typedef typename MatrixType::Scalar Scalar;
295 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
296 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
297 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
298 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
299 Options = MatrixType::Options
307 if (svd.cols() != m_qr.rows() || svd.rows() != m_qr.cols())
310 ::new (&m_qr)
QRType(svd.cols(), svd.rows());
312 if (svd.m_computeFullV) m_workspace.resize(svd.cols());
313 else if (svd.m_computeThinV) m_workspace.resize(svd.rows());
314 m_adjoint.resize(svd.cols(), svd.rows());
319 if(matrix.cols() > matrix.rows())
321 m_adjoint = matrix.adjoint();
322 m_qr.compute(m_adjoint);
324 svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).
template triangularView<Upper>().adjoint();
325 if(svd.m_computeFullV) m_qr.householderQ().evalTo(svd.m_matrixV, m_workspace);
326 else if(svd.m_computeThinV)
328 svd.m_matrixV.setIdentity(matrix.cols(), matrix.rows());
329 m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixV, m_workspace);
331 if(svd.
computeU()) svd.m_matrixU.setIdentity(matrix.rows(), matrix.rows());
340 TransposeTypeWithSameStorageOrder m_adjoint;
349 template<
typename MatrixType,
int QRPreconditioner>
353 typedef typename MatrixType::RealScalar RealScalar;
357 template<
typename MatrixType,
int QRPreconditioner>
361 typedef typename MatrixType::Scalar Scalar;
362 typedef typename MatrixType::RealScalar RealScalar;
369 RealScalar n = sqrt(numext::abs2(work_matrix.
coeff(p,p)) + numext::abs2(work_matrix.
coeff(q,p)));
371 const RealScalar considerAsZero = (std::numeric_limits<RealScalar>::min)();
379 if(abs(numext::imag(work_matrix.
coeff(p,q)))>considerAsZero)
382 z = abs(work_matrix.
coeff(p,q)) / work_matrix.
coeff(p,q);
383 work_matrix.row(p) *= z;
384 if(svd.
computeU()) svd.m_matrixU.col(p) *= conj(z);
386 if(abs(numext::imag(work_matrix.
coeff(q,q)))>considerAsZero)
388 z = abs(work_matrix.
coeff(q,q)) / work_matrix.
coeff(q,q);
389 work_matrix.row(q) *= z;
390 if(svd.
computeU()) svd.m_matrixU.col(q) *= conj(z);
396 rot.c() = conj(work_matrix.
coeff(p,p)) / n;
397 rot.s() = work_matrix.
coeff(q,p) / n;
398 work_matrix.applyOnTheLeft(p,q,rot);
400 if(abs(numext::imag(work_matrix.
coeff(p,q)))>considerAsZero)
402 z = abs(work_matrix.
coeff(p,q)) / work_matrix.
coeff(p,q);
403 work_matrix.col(q) *= z;
404 if(svd.
computeV()) svd.m_matrixV.col(q) *= z;
406 if(abs(numext::imag(work_matrix.
coeff(q,q)))>considerAsZero)
408 z = abs(work_matrix.
coeff(q,q)) / work_matrix.
coeff(q,q);
409 work_matrix.row(q) *= z;
410 if(svd.
computeU()) svd.m_matrixU.col(q) *= conj(z);
415 maxDiagEntry = numext::maxi<RealScalar>(maxDiagEntry,numext::maxi<RealScalar>(abs(work_matrix.
coeff(p,p)), abs(work_matrix.
coeff(q,q))));
417 RealScalar threshold = numext::maxi<RealScalar>(considerAsZero, precision * maxDiagEntry);
418 return abs(work_matrix.
coeff(p,q))>threshold || abs(work_matrix.
coeff(q,p)) > threshold;
422 template<
typename _MatrixType,
int QRPreconditioner>
425 typedef _MatrixType MatrixType;
483 template<
typename _MatrixType,
int QRPreconditioner>
class JacobiSVD 484 :
public SVDBase<JacobiSVD<_MatrixType,QRPreconditioner> >
489 typedef _MatrixType MatrixType;
490 typedef typename MatrixType::Scalar Scalar;
493 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
494 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
495 DiagSizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime,ColsAtCompileTime),
496 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
497 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
498 MaxDiagSizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_FIXED(MaxRowsAtCompileTime,MaxColsAtCompileTime),
499 MatrixOptions = MatrixType::Options
502 typedef typename Base::MatrixUType MatrixUType;
503 typedef typename Base::MatrixVType MatrixVType;
504 typedef typename Base::SingularValuesType SingularValuesType;
508 typedef Matrix<Scalar, DiagSizeAtCompileTime, DiagSizeAtCompileTime,
509 MatrixOptions, MaxDiagSizeAtCompileTime, MaxDiagSizeAtCompileTime>
529 allocate(rows, cols, computationOptions);
542 explicit JacobiSVD(
const MatrixType& matrix,
unsigned int computationOptions = 0)
544 compute(matrix, computationOptions);
557 JacobiSVD& compute(
const MatrixType& matrix,
unsigned int computationOptions);
567 return compute(matrix, m_computationOptions);
570 using Base::computeU;
571 using Base::computeV;
577 void allocate(
Index rows,
Index cols,
unsigned int computationOptions);
580 using Base::m_matrixU;
581 using Base::m_matrixV;
582 using Base::m_singularValues;
583 using Base::m_isInitialized;
584 using Base::m_isAllocated;
585 using Base::m_usePrescribedThreshold;
586 using Base::m_computeFullU;
587 using Base::m_computeThinU;
588 using Base::m_computeFullV;
589 using Base::m_computeThinV;
590 using Base::m_computationOptions;
591 using Base::m_nonzeroSingularValues;
594 using Base::m_diagSize;
595 using Base::m_prescribedThreshold;
596 WorkMatrixType m_workMatrix;
598 template<
typename __MatrixType,
int _QRPreconditioner,
bool _IsComplex>
600 template<
typename __MatrixType,
int _QRPreconditioner,
int _Case,
bool _DoAnything>
605 MatrixType m_scaledMatrix;
608 template<
typename MatrixType,
int QRPreconditioner>
611 eigen_assert(rows >= 0 && cols >= 0);
616 computationOptions == m_computationOptions)
623 m_isInitialized =
false;
624 m_isAllocated =
true;
625 m_computationOptions = computationOptions;
626 m_computeFullU = (computationOptions &
ComputeFullU) != 0;
627 m_computeThinU = (computationOptions &
ComputeThinU) != 0;
628 m_computeFullV = (computationOptions &
ComputeFullV) != 0;
629 m_computeThinV = (computationOptions &
ComputeThinV) != 0;
630 eigen_assert(!(m_computeFullU && m_computeThinU) &&
"JacobiSVD: you can't ask for both full and thin U");
631 eigen_assert(!(m_computeFullV && m_computeThinV) &&
"JacobiSVD: you can't ask for both full and thin V");
632 eigen_assert(EIGEN_IMPLIES(m_computeThinU || m_computeThinV, MatrixType::ColsAtCompileTime==
Dynamic) &&
633 "JacobiSVD: thin U and V are only available when your matrix has a dynamic number of columns.");
636 eigen_assert(!(m_computeThinU || m_computeThinV) &&
637 "JacobiSVD: can't compute thin U or thin V with the FullPivHouseholderQR preconditioner. " 638 "Use the ColPivHouseholderQR preconditioner instead.");
640 m_diagSize = (std::min)(m_rows, m_cols);
641 m_singularValues.resize(m_diagSize);
643 m_matrixU.resize(m_rows, m_computeFullU ? m_rows
644 : m_computeThinU ? m_diagSize
647 m_matrixV.resize(m_cols, m_computeFullV ? m_cols
648 : m_computeThinV ? m_diagSize
650 m_workMatrix.resize(m_diagSize, m_diagSize);
652 if(m_cols>m_rows) m_qr_precond_morecols.allocate(*
this);
653 if(m_rows>m_cols) m_qr_precond_morerows.allocate(*
this);
654 if(m_rows!=m_cols) m_scaledMatrix.resize(rows,cols);
657 template<
typename MatrixType,
int QRPreconditioner>
662 allocate(matrix.rows(), matrix.cols(), computationOptions);
669 const RealScalar considerAsZero = (std::numeric_limits<RealScalar>::min)();
672 RealScalar scale = matrix.cwiseAbs().maxCoeff();
673 if(scale==RealScalar(0)) scale = RealScalar(1);
679 m_scaledMatrix = matrix / scale;
680 m_qr_precond_morecols.run(*
this, m_scaledMatrix);
681 m_qr_precond_morerows.run(*
this, m_scaledMatrix);
685 m_workMatrix = matrix.block(0,0,m_diagSize,m_diagSize) / scale;
686 if(m_computeFullU) m_matrixU.setIdentity(m_rows,m_rows);
687 if(m_computeThinU) m_matrixU.setIdentity(m_rows,m_diagSize);
688 if(m_computeFullV) m_matrixV.setIdentity(m_cols,m_cols);
689 if(m_computeThinV) m_matrixV.setIdentity(m_cols, m_diagSize);
693 RealScalar maxDiagEntry = m_workMatrix.cwiseAbs().diagonal().maxCoeff();
695 bool finished =
false;
702 for(
Index p = 1; p < m_diagSize; ++p)
704 for(
Index q = 0; q < p; ++q)
709 RealScalar threshold = numext::maxi<RealScalar>(considerAsZero, precision * maxDiagEntry);
710 if(abs(m_workMatrix.coeff(p,q))>threshold || abs(m_workMatrix.coeff(q,p)) > threshold)
718 internal::real_2x2_jacobi_svd(m_workMatrix, p, q, &j_left, &j_right);
721 m_workMatrix.applyOnTheLeft(p,q,j_left);
722 if(computeU()) m_matrixU.applyOnTheRight(p,q,j_left.
transpose());
724 m_workMatrix.applyOnTheRight(p,q,j_right);
725 if(computeV()) m_matrixV.applyOnTheRight(p,q,j_right);
728 maxDiagEntry = numext::maxi<RealScalar>(maxDiagEntry,numext::maxi<RealScalar>(abs(m_workMatrix.coeff(p,p)), abs(m_workMatrix.coeff(q,q))));
737 for(
Index i = 0; i < m_diagSize; ++i)
744 RealScalar a = abs(m_workMatrix.coeff(i,i));
745 m_singularValues.coeffRef(i) = abs(a);
746 if(computeU()) m_matrixU.col(i) *= m_workMatrix.coeff(i,i)/a;
751 RealScalar a = numext::real(m_workMatrix.coeff(i,i));
752 m_singularValues.coeffRef(i) = abs(a);
753 if(computeU() && (a<RealScalar(0))) m_matrixU.col(i) = -m_matrixU.col(i);
757 m_singularValues *= scale;
761 m_nonzeroSingularValues = m_diagSize;
762 for(
Index i = 0; i < m_diagSize; i++)
765 RealScalar maxRemainingSingularValue = m_singularValues.tail(m_diagSize-i).maxCoeff(&pos);
766 if(maxRemainingSingularValue == RealScalar(0))
768 m_nonzeroSingularValues = i;
774 std::swap(m_singularValues.coeffRef(i), m_singularValues.coeffRef(pos));
775 if(computeU()) m_matrixU.col(pos).swap(m_matrixU.col(i));
776 if(computeV()) m_matrixV.col(pos).swap(m_matrixV.col(i));
780 m_isInitialized =
true;
791 template<
typename Derived>
800 #endif // EIGEN_JACOBISVD_H Used in JacobiSVD to indicate that the square matrix U is to be computed.
Definition: Constants.h:383
Do not specify what is to be done if the SVD of a non-square matrix is asked for. ...
Definition: Constants.h:415
Used in JacobiSVD to indicate that the thin matrix V is to be computed.
Definition: Constants.h:389
Namespace containing all symbols from the Eigen library.
Definition: bench_norm.cpp:85
Definition: ForwardDeclarations.h:263
Holds information about the various numeric (i.e.
Definition: NumTraits.h:150
Definition: JacobiSVD.h:21
Use a QR decomposition without pivoting as the first step.
Definition: Constants.h:417
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar & coeffRef(Index rowId, Index colId)
This is an overloaded version of DenseCoeffsBase<Derived,WriteAccessors>::coeffRef(Index,Index) const provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts.
Definition: PlainObjectBase.h:177
bool computeV() const
Definition: SVDBase.h:190
Use a QR decomposition with column pivoting as the first step.
Definition: Constants.h:419
Base class of SVD algorithms.
Definition: SVDBase.h:48
JacobiSVD< PlainObject > jacobiSvd(unsigned int computationOptions=0) const
Definition: JacobiSVD.h:793
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar & coeff(Index rowId, Index colId) const
This is an overloaded version of DenseCoeffsBase<Derived,ReadOnlyAccessors>::coeff(Index,Index) const provided to by-pass the creation of an evaluator of the expression, thus saving compilation efforts.
Definition: PlainObjectBase.h:154
JacobiSVD()
Default Constructor.
Definition: JacobiSVD.h:517
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:33
Use a QR decomposition with full pivoting as the first step.
Definition: Constants.h:421
Definition: JacobiSVD.h:49
Definition: BandTriangularSolver.h:13
JacobiSVD & compute(const MatrixType &matrix)
Method performing the decomposition of given matrix using current options.
Definition: JacobiSVD.h:565
Two-sided Jacobi SVD decomposition of a rectangular matrix.
Definition: ForwardDeclarations.h:258
JacobiRotation transpose() const
Returns the transposed transformation.
Definition: Jacobi.h:59
bool computeU() const
Definition: SVDBase.h:188
JacobiSVD & compute(const MatrixType &matrix, unsigned int computationOptions)
Method performing the decomposition of given matrix using custom options.
Definition: JacobiSVD.h:659
const int Dynamic
This value means that a positive quantity (e.g., a size) is not known at compile-time, and that instead the value is stored in some runtime variable.
Definition: Constants.h:21
Generic expression where a coefficient-wise unary operator is applied to an expression.
Definition: CwiseUnaryOp.h:55
Used in JacobiSVD to indicate that the square matrix V is to be computed.
Definition: Constants.h:387
Used in JacobiSVD to indicate that the thin matrix U is to be computed.
Definition: Constants.h:385
JacobiSVD(Index rows, Index cols, unsigned int computationOptions=0)
Default Constructor with memory preallocation.
Definition: JacobiSVD.h:527
Definition: ForwardDeclarations.h:17
Definition: JacobiSVD.h:33
JacobiSVD(const MatrixType &matrix, unsigned int computationOptions=0)
Constructor performing the decomposition of given matrix.
Definition: JacobiSVD.h:542
JacobiRotation adjoint() const
Returns the adjoint transformation.
Definition: Jacobi.h:62