11 #ifndef EIGEN_JACOBISVD_H
12 #define EIGEN_JACOBISVD_H
19 template<
typename MatrixType,
int QRPreconditioner,
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,
47 template<
typename MatrixType,
int QRPreconditioner,
int Case,
51 template<
typename MatrixType,
int QRPreconditioner,
int Case>
64 template<
typename MatrixType>
71 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
72 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime
78 if (
svd.rows() != m_qr.rows() ||
svd.cols() != m_qr.cols())
83 if (
svd.m_computeFullU) m_workspace.resize(
svd.rows());
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();
104 template<
typename MatrixType>
111 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
112 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
113 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
114 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
115 Options = MatrixType::Options
119 Scalar, ColsAtCompileTime, RowsAtCompileTime, Options, MaxColsAtCompileTime, MaxRowsAtCompileTime
124 if (
svd.cols() != m_qr.rows() ||
svd.rows() != m_qr.cols())
129 m_adjoint.resize(
svd.cols(),
svd.rows());
130 if (
svd.m_computeFullV) m_workspace.resize(
svd.cols());
137 m_adjoint =
matrix.adjoint();
138 m_qr.compute(m_adjoint);
139 svd.m_workMatrix = m_qr.matrixQR().block(0,0,
matrix.rows(),
matrix.rows()).template triangularView<Upper>().adjoint();
140 if(
svd.m_computeFullV) m_qr.matrixQ().evalTo(
svd.m_matrixV, m_workspace);
141 if(
svd.computeU())
svd.m_matrixU = m_qr.colsPermutation();
155 template<
typename MatrixType>
161 if (
svd.rows() != m_qr.rows() ||
svd.cols() != m_qr.cols())
166 if (
svd.m_computeFullU) m_workspace.resize(
svd.rows());
167 else if (
svd.m_computeThinU) m_workspace.resize(
svd.cols());
175 svd.m_workMatrix = m_qr.matrixQR().block(0,0,
matrix.cols(),
matrix.cols()).template triangularView<Upper>();
176 if(
svd.m_computeFullU) m_qr.householderQ().evalTo(
svd.m_matrixU, m_workspace);
177 else if(
svd.m_computeThinU)
180 m_qr.householderQ().applyThisOnTheLeft(
svd.m_matrixU, m_workspace);
182 if(
svd.computeV())
svd.m_matrixV = m_qr.colsPermutation();
194 template<
typename MatrixType>
201 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
202 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
203 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
204 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
205 Options = MatrixType::Options
209 Scalar, ColsAtCompileTime, RowsAtCompileTime, Options, MaxColsAtCompileTime, MaxRowsAtCompileTime
214 if (
svd.cols() != m_qr.rows() ||
svd.rows() != m_qr.cols())
219 if (
svd.m_computeFullV) m_workspace.resize(
svd.cols());
220 else if (
svd.m_computeThinV) m_workspace.resize(
svd.rows());
221 m_adjoint.resize(
svd.cols(),
svd.rows());
228 m_adjoint =
matrix.adjoint();
229 m_qr.compute(m_adjoint);
231 svd.m_workMatrix = m_qr.matrixQR().block(0,0,
matrix.rows(),
matrix.rows()).template triangularView<Upper>().adjoint();
232 if(
svd.m_computeFullV) m_qr.householderQ().evalTo(
svd.m_matrixV, m_workspace);
233 else if(
svd.m_computeThinV)
236 m_qr.householderQ().applyThisOnTheLeft(
svd.m_matrixV, m_workspace);
238 if(
svd.computeU())
svd.m_matrixU = m_qr.colsPermutation();
253 template<
typename MatrixType>
259 if (
svd.rows() != m_qr.rows() ||
svd.cols() != m_qr.cols())
264 if (
svd.m_computeFullU) m_workspace.resize(
svd.rows());
265 else if (
svd.m_computeThinU) m_workspace.resize(
svd.cols());
273 svd.m_workMatrix = m_qr.matrixQR().block(0,0,
matrix.cols(),
matrix.cols()).template triangularView<Upper>();
274 if(
svd.m_computeFullU) m_qr.householderQ().evalTo(
svd.m_matrixU, m_workspace);
275 else if(
svd.m_computeThinU)
278 m_qr.householderQ().applyThisOnTheLeft(
svd.m_matrixU, m_workspace);
291 template<
typename MatrixType>
298 RowsAtCompileTime = MatrixType::RowsAtCompileTime,
299 ColsAtCompileTime = MatrixType::ColsAtCompileTime,
300 MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
301 MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
302 Options = MatrixType::Options
306 Scalar, ColsAtCompileTime, RowsAtCompileTime, Options, MaxColsAtCompileTime, MaxRowsAtCompileTime
311 if (
svd.cols() != m_qr.rows() ||
svd.rows() != m_qr.cols())
316 if (
svd.m_computeFullV) m_workspace.resize(
svd.cols());
317 else if (
svd.m_computeThinV) m_workspace.resize(
svd.rows());
318 m_adjoint.resize(
svd.cols(),
svd.rows());
325 m_adjoint =
matrix.adjoint();
326 m_qr.compute(m_adjoint);
328 svd.m_workMatrix = m_qr.matrixQR().block(0,0,
matrix.rows(),
matrix.rows()).template triangularView<Upper>().adjoint();
329 if(
svd.m_computeFullV) m_qr.householderQ().evalTo(
svd.m_matrixV, m_workspace);
330 else if(
svd.m_computeThinV)
333 m_qr.householderQ().applyThisOnTheLeft(
svd.m_matrixV, m_workspace);
353 template<
typename MatrixType,
int QRPreconditioner>
361 template<
typename MatrixType,
int QRPreconditioner>
387 work_matrix.row(
p) *=
z;
393 work_matrix.row(
q) *=
z;
402 work_matrix.applyOnTheLeft(
p,
q,
rot);
403 if(
svd.computeU())
svd.m_matrixU.applyOnTheRight(
p,
q,
rot.adjoint());
407 work_matrix.col(
q) *=
z;
408 if(
svd.computeV())
svd.m_matrixV.col(
q) *=
z;
413 work_matrix.row(
q) *=
z;
419 maxDiagEntry = numext::maxi<RealScalar>(maxDiagEntry,numext::maxi<RealScalar>(
abs(work_matrix.
coeff(
p,
p)),
abs(work_matrix.
coeff(
q,
q))));
426 template<
typename _MatrixType,
int QRPreconditioner>
488 template<
typename _MatrixType,
int QRPreconditioner>
class JacobiSVD
489 :
public SVDBase<JacobiSVD<_MatrixType,QRPreconditioner> >
604 template<
typename __MatrixType,
int _QRPreconditioner,
bool _IsComplex>
606 template<
typename __MatrixType,
int _QRPreconditioner,
int _Case,
bool _DoAnything>
614 template<
typename MatrixType,
int QRPreconditioner>
622 computationOptions == m_computationOptions)
630 m_isInitialized =
false;
631 m_isAllocated =
true;
632 m_computationOptions = computationOptions;
633 m_computeFullU = (computationOptions &
ComputeFullU) != 0;
634 m_computeThinU = (computationOptions &
ComputeThinU) != 0;
635 m_computeFullV = (computationOptions &
ComputeFullV) != 0;
636 m_computeThinV = (computationOptions &
ComputeThinV) != 0;
637 eigen_assert(!(m_computeFullU && m_computeThinU) &&
"JacobiSVD: you can't ask for both full and thin U");
638 eigen_assert(!(m_computeFullV && m_computeThinV) &&
"JacobiSVD: you can't ask for both full and thin V");
640 "JacobiSVD: thin U and V are only available when your matrix has a dynamic number of columns.");
644 "JacobiSVD: can't compute thin U or thin V with the FullPivHouseholderQR preconditioner. "
645 "Use the ColPivHouseholderQR preconditioner instead.");
647 m_diagSize = (
std::min)(m_rows, m_cols);
648 m_singularValues.resize(m_diagSize);
650 m_matrixU.resize(m_rows, m_computeFullU ? m_rows
651 : m_computeThinU ? m_diagSize
654 m_matrixV.resize(m_cols, m_computeFullV ? m_cols
655 : m_computeThinV ? m_diagSize
657 m_workMatrix.resize(m_diagSize, m_diagSize);
659 if(m_cols>m_rows) m_qr_precond_morecols.allocate(*
this);
660 if(m_rows>m_cols) m_qr_precond_morerows.allocate(*
this);
661 if(m_rows!=m_cols) m_scaledMatrix.resize(
rows,
cols);
664 template<
typename MatrixType,
int QRPreconditioner>
669 allocate(
matrix.rows(),
matrix.cols(), computationOptions);
681 m_isInitialized =
true;
692 m_qr_precond_morecols.run(*
this, m_scaledMatrix);
693 m_qr_precond_morerows.run(*
this, m_scaledMatrix);
697 m_workMatrix =
matrix.block(0,0,m_diagSize,m_diagSize) /
scale;
698 if(m_computeFullU) m_matrixU.setIdentity(m_rows,m_rows);
699 if(m_computeThinU) m_matrixU.setIdentity(m_rows,m_diagSize);
700 if(m_computeFullV) m_matrixV.setIdentity(m_cols,m_cols);
701 if(m_computeThinV) m_matrixV.setIdentity(m_cols, m_diagSize);
705 RealScalar maxDiagEntry = m_workMatrix.cwiseAbs().diagonal().maxCoeff();
707 bool finished =
false;
714 for(
Index p = 1;
p < m_diagSize; ++
p)
722 if(
abs(m_workMatrix.coeff(
p,
q))>threshold ||
abs(m_workMatrix.coeff(
q,
p)) > threshold)
733 m_workMatrix.applyOnTheLeft(
p,
q,j_left);
734 if(computeU()) m_matrixU.applyOnTheRight(
p,
q,j_left.
transpose());
736 m_workMatrix.applyOnTheRight(
p,
q,j_right);
737 if(computeV()) m_matrixV.applyOnTheRight(
p,
q,j_right);
740 maxDiagEntry = numext::maxi<RealScalar>(maxDiagEntry,numext::maxi<RealScalar>(
abs(m_workMatrix.coeff(
p,
p)),
abs(m_workMatrix.coeff(
q,
q))));
749 for(
Index i = 0;
i < m_diagSize; ++
i)
757 m_singularValues.coeffRef(
i) =
abs(
a);
758 if(computeU()) m_matrixU.col(
i) *= m_workMatrix.coeff(
i,
i)/
a;
764 m_singularValues.coeffRef(
i) =
abs(
a);
765 if(computeU() && (
a<
RealScalar(0))) m_matrixU.col(
i) = -m_matrixU.col(
i);
769 m_singularValues *=
scale;
773 m_nonzeroSingularValues = m_diagSize;
774 for(
Index i = 0;
i < m_diagSize;
i++)
777 RealScalar maxRemainingSingularValue = m_singularValues.tail(m_diagSize-
i).maxCoeff(&
pos);
778 if(maxRemainingSingularValue ==
RealScalar(0))
780 m_nonzeroSingularValues =
i;
786 std::swap(m_singularValues.coeffRef(
i), m_singularValues.coeffRef(
pos));
787 if(computeU()) m_matrixU.col(
pos).swap(m_matrixU.col(
i));
788 if(computeV()) m_matrixV.col(
pos).swap(m_matrixV.col(
i));
792 m_isInitialized =
true;
803 template<
typename Derived>
812 #endif // EIGEN_JACOBISVD_H