aboutsummaryrefslogtreecommitdiffhomepage
path: root/Eigen/src/SVD/JacobiSVD.h
diff options
context:
space:
mode:
Diffstat (limited to 'Eigen/src/SVD/JacobiSVD.h')
-rw-r--r--Eigen/src/SVD/JacobiSVD.h246
1 files changed, 126 insertions, 120 deletions
diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h
index 56ffea131..d180db7db 100644
--- a/Eigen/src/SVD/JacobiSVD.h
+++ b/Eigen/src/SVD/JacobiSVD.h
@@ -25,12 +25,12 @@
#ifndef EIGEN_JACOBISVD_H
#define EIGEN_JACOBISVD_H
+namespace internal {
// forward declaration (needed by ICC)
// the empty body is required by MSVC
template<typename MatrixType, int QRPreconditioner,
bool IsComplex = NumTraits<typename MatrixType::Scalar>::IsComplex>
-struct ei_svd_precondition_2x2_block_to_be_real {};
-
+struct svd_precondition_2x2_block_to_be_real {};
/*** QR preconditioners (R-SVD)
***
@@ -42,7 +42,7 @@ struct ei_svd_precondition_2x2_block_to_be_real {};
enum { PreconditionIfMoreColsThanRows, PreconditionIfMoreRowsThanCols };
template<typename MatrixType, int QRPreconditioner, int Case>
-struct ei_qr_preconditioner_should_do_anything
+struct qr_preconditioner_should_do_anything
{
enum { a = MatrixType::RowsAtCompileTime != Dynamic &&
MatrixType::ColsAtCompileTime != Dynamic &&
@@ -57,11 +57,11 @@ struct ei_qr_preconditioner_should_do_anything
};
template<typename MatrixType, int QRPreconditioner, int Case,
- bool DoAnything = ei_qr_preconditioner_should_do_anything<MatrixType, QRPreconditioner, Case>::ret
-> struct ei_qr_preconditioner_impl {};
+ bool DoAnything = qr_preconditioner_should_do_anything<MatrixType, QRPreconditioner, Case>::ret
+> struct qr_preconditioner_impl {};
template<typename MatrixType, int QRPreconditioner, int Case>
-struct ei_qr_preconditioner_impl<MatrixType, QRPreconditioner, Case, false>
+struct qr_preconditioner_impl<MatrixType, QRPreconditioner, Case, false>
{
static bool run(JacobiSVD<MatrixType, QRPreconditioner>&, const MatrixType&)
{
@@ -72,7 +72,7 @@ struct ei_qr_preconditioner_impl<MatrixType, QRPreconditioner, Case, false>
/*** preconditioner using FullPivHouseholderQR ***/
template<typename MatrixType>
-struct ei_qr_preconditioner_impl<MatrixType, FullPivHouseholderQRPreconditioner, PreconditionIfMoreRowsThanCols, true>
+struct qr_preconditioner_impl<MatrixType, FullPivHouseholderQRPreconditioner, PreconditionIfMoreRowsThanCols, true>
{
static bool run(JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner>& svd, const MatrixType& matrix)
{
@@ -89,7 +89,7 @@ struct ei_qr_preconditioner_impl<MatrixType, FullPivHouseholderQRPreconditioner,
};
template<typename MatrixType>
-struct ei_qr_preconditioner_impl<MatrixType, FullPivHouseholderQRPreconditioner, PreconditionIfMoreColsThanRows, true>
+struct qr_preconditioner_impl<MatrixType, FullPivHouseholderQRPreconditioner, PreconditionIfMoreColsThanRows, true>
{
static bool run(JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner>& svd, const MatrixType& matrix)
{
@@ -111,7 +111,7 @@ struct ei_qr_preconditioner_impl<MatrixType, FullPivHouseholderQRPreconditioner,
/*** preconditioner using ColPivHouseholderQR ***/
template<typename MatrixType>
-struct ei_qr_preconditioner_impl<MatrixType, ColPivHouseholderQRPreconditioner, PreconditionIfMoreRowsThanCols, true>
+struct qr_preconditioner_impl<MatrixType, ColPivHouseholderQRPreconditioner, PreconditionIfMoreRowsThanCols, true>
{
static bool run(JacobiSVD<MatrixType, ColPivHouseholderQRPreconditioner>& svd, const MatrixType& matrix)
{
@@ -132,7 +132,7 @@ struct ei_qr_preconditioner_impl<MatrixType, ColPivHouseholderQRPreconditioner,
};
template<typename MatrixType>
-struct ei_qr_preconditioner_impl<MatrixType, ColPivHouseholderQRPreconditioner, PreconditionIfMoreColsThanRows, true>
+struct qr_preconditioner_impl<MatrixType, ColPivHouseholderQRPreconditioner, PreconditionIfMoreColsThanRows, true>
{
static bool run(JacobiSVD<MatrixType, ColPivHouseholderQRPreconditioner>& svd, const MatrixType& matrix)
{
@@ -158,7 +158,7 @@ struct ei_qr_preconditioner_impl<MatrixType, ColPivHouseholderQRPreconditioner,
/*** preconditioner using HouseholderQR ***/
template<typename MatrixType>
-struct ei_qr_preconditioner_impl<MatrixType, HouseholderQRPreconditioner, PreconditionIfMoreRowsThanCols, true>
+struct qr_preconditioner_impl<MatrixType, HouseholderQRPreconditioner, PreconditionIfMoreRowsThanCols, true>
{
static bool run(JacobiSVD<MatrixType, HouseholderQRPreconditioner>& svd, const MatrixType& matrix)
{
@@ -179,7 +179,7 @@ struct ei_qr_preconditioner_impl<MatrixType, HouseholderQRPreconditioner, Precon
};
template<typename MatrixType>
-struct ei_qr_preconditioner_impl<MatrixType, HouseholderQRPreconditioner, PreconditionIfMoreColsThanRows, true>
+struct qr_preconditioner_impl<MatrixType, HouseholderQRPreconditioner, PreconditionIfMoreColsThanRows, true>
{
static bool run(JacobiSVD<MatrixType, HouseholderQRPreconditioner>& svd, const MatrixType& matrix)
{
@@ -202,7 +202,90 @@ struct ei_qr_preconditioner_impl<MatrixType, HouseholderQRPreconditioner, Precon
}
};
+/*** 2x2 SVD implementation
+ ***
+ *** JacobiSVD consists in performing a series of 2x2 SVD subproblems
+ ***/
+
+template<typename MatrixType, int QRPreconditioner>
+struct svd_precondition_2x2_block_to_be_real<MatrixType, QRPreconditioner, false>
+{
+ typedef JacobiSVD<MatrixType, QRPreconditioner> SVD;
+ typedef typename SVD::Index Index;
+ static void run(typename SVD::WorkMatrixType&, SVD&, Index, Index) {}
+};
+
+template<typename MatrixType, int QRPreconditioner>
+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;
+ typedef typename SVD::Index Index;
+ static void run(typename SVD::WorkMatrixType& work_matrix, SVD& svd, Index p, Index q)
+ {
+ Scalar z;
+ JacobiRotation<Scalar> rot;
+ RealScalar n = sqrt(abs2(work_matrix.coeff(p,p)) + abs2(work_matrix.coeff(q,p)));
+ if(n==0)
+ {
+ 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);
+ z = abs(work_matrix.coeff(q,q)) / work_matrix.coeff(q,q);
+ work_matrix.row(q) *= z;
+ if(svd.computeU()) svd.m_matrixU.col(q) *= conj(z);
+ }
+ else
+ {
+ rot.c() = conj(work_matrix.coeff(p,p)) / n;
+ 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))
+ {
+ Scalar 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))
+ {
+ z = abs(work_matrix.coeff(q,q)) / work_matrix.coeff(q,q);
+ work_matrix.row(q) *= z;
+ if(svd.computeU()) svd.m_matrixU.col(q) *= conj(z);
+ }
+ }
+ }
+};
+
+template<typename MatrixType, typename RealScalar, typename Index>
+void real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q,
+ JacobiRotation<RealScalar> *j_left,
+ JacobiRotation<RealScalar> *j_right)
+{
+ Matrix<RealScalar,2,2> m;
+ m << real(matrix.coeff(p,p)), real(matrix.coeff(p,q)),
+ real(matrix.coeff(q,p)), real(matrix.coeff(q,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(t == RealScalar(0))
+ {
+ rot1.c() = 0;
+ rot1.s() = d > 0 ? 1 : -1;
+ }
+ else
+ {
+ RealScalar u = d / t;
+ rot1.c() = RealScalar(1) / sqrt(1 + abs2(u));
+ rot1.s() = rot1.c() * u;
+ }
+ m.applyOnTheLeft(0,1,rot1);
+ j_right->makeJacobi(m,0,1);
+ *j_left = rot1 * j_right->transpose();
+}
+} // end namespace internal
/** \ingroup SVD_Module
*
@@ -281,9 +364,9 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
typedef Matrix<Scalar, ColsAtCompileTime, ColsAtCompileTime,
MatrixOptions, MaxColsAtCompileTime, MaxColsAtCompileTime>
MatrixVType;
- typedef typename ei_plain_diag_type<MatrixType, RealScalar>::type SingularValuesType;
- typedef typename ei_plain_row_type<MatrixType>::type RowType;
- typedef typename ei_plain_col_type<MatrixType>::type ColType;
+ typedef typename internal::plain_diag_type<MatrixType, RealScalar>::type SingularValuesType;
+ typedef typename internal::plain_row_type<MatrixType>::type RowType;
+ typedef typename internal::plain_col_type<MatrixType>::type ColType;
typedef Matrix<Scalar, DiagSizeAtCompileTime, DiagSizeAtCompileTime,
MatrixOptions, MaxDiagSizeAtCompileTime, MaxDiagSizeAtCompileTime>
WorkMatrixType;
@@ -345,8 +428,8 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
*/
const MatrixUType& matrixU() const
{
- ei_assert(m_isInitialized && "JacobiSVD is not initialized.");
- ei_assert(computeU() && "This JacobiSVD decomposition didn't compute U. Did you ask for it?");
+ eigen_assert(m_isInitialized && "JacobiSVD is not initialized.");
+ eigen_assert(computeU() && "This JacobiSVD decomposition didn't compute U. Did you ask for it?");
return m_matrixU;
}
@@ -361,8 +444,8 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
*/
const MatrixVType& matrixV() const
{
- ei_assert(m_isInitialized && "JacobiSVD is not initialized.");
- ei_assert(computeV() && "This JacobiSVD decomposition didn't compute V. Did you ask for it?");
+ eigen_assert(m_isInitialized && "JacobiSVD is not initialized.");
+ eigen_assert(computeV() && "This JacobiSVD decomposition didn't compute V. Did you ask for it?");
return m_matrixV;
}
@@ -373,7 +456,7 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
*/
const SingularValuesType& singularValues() const
{
- ei_assert(m_isInitialized && "JacobiSVD is not initialized.");
+ eigen_assert(m_isInitialized && "JacobiSVD is not initialized.");
return m_singularValues;
}
@@ -392,18 +475,18 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
* In other words, the returned solution is guaranteed to minimize the Euclidean norm \f$ \Vert A x - b \Vert \f$.
*/
template<typename Rhs>
- inline const ei_solve_retval<JacobiSVD, Rhs>
+ inline const internal::solve_retval<JacobiSVD, Rhs>
solve(const MatrixBase<Rhs>& b) const
{
- ei_assert(m_isInitialized && "JacobiSVD is not initialized.");
- ei_assert(computeU() && computeV() && "JacobiSVD::solve() requires both unitaries U and V to be computed (thin unitaries suffice).");
- return ei_solve_retval<JacobiSVD, Rhs>(*this, b.derived());
+ eigen_assert(m_isInitialized && "JacobiSVD is not initialized.");
+ eigen_assert(computeU() && computeV() && "JacobiSVD::solve() requires both unitaries U and V to be computed (thin unitaries suffice).");
+ return internal::solve_retval<JacobiSVD, Rhs>(*this, b.derived());
}
/** \returns the number of singular values that are not exactly 0 */
Index nonzeroSingularValues() const
{
- ei_assert(m_isInitialized && "JacobiSVD is not initialized.");
+ eigen_assert(m_isInitialized && "JacobiSVD is not initialized.");
return m_nonzeroSingularValues;
}
@@ -424,9 +507,9 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
Index m_nonzeroSingularValues, m_rows, m_cols, m_diagSize;
template<typename __MatrixType, int _QRPreconditioner, bool _IsComplex>
- friend struct ei_svd_precondition_2x2_block_to_be_real;
+ friend struct internal::svd_precondition_2x2_block_to_be_real;
template<typename __MatrixType, int _QRPreconditioner, int _Case, bool _DoAnything>
- friend struct ei_qr_preconditioner_impl;
+ friend struct internal::qr_preconditioner_impl;
};
template<typename MatrixType, int QRPreconditioner>
@@ -439,13 +522,13 @@ void JacobiSVD<MatrixType, QRPreconditioner>::allocate(Index rows, Index cols, u
m_computeThinU = (computationOptions & ComputeThinU) != 0;
m_computeFullV = (computationOptions & ComputeFullV) != 0;
m_computeThinV = (computationOptions & ComputeThinV) != 0;
- ei_assert(!(m_computeFullU && m_computeThinU) && "JacobiSVD: you can't ask for both full and thin U");
- ei_assert(!(m_computeFullV && m_computeThinV) && "JacobiSVD: you can't ask for both full and thin V");
- ei_assert(EIGEN_IMPLIES(m_computeThinU || m_computeThinV, MatrixType::ColsAtCompileTime==Dynamic) &&
+ eigen_assert(!(m_computeFullU && m_computeThinU) && "JacobiSVD: you can't ask for both full and thin U");
+ eigen_assert(!(m_computeFullV && m_computeThinV) && "JacobiSVD: you can't ask for both full and thin V");
+ eigen_assert(EIGEN_IMPLIES(m_computeThinU || m_computeThinV, MatrixType::ColsAtCompileTime==Dynamic) &&
"JacobiSVD: thin U and V are only available when your matrix has a dynamic number of columns.");
if (QRPreconditioner == FullPivHouseholderQRPreconditioner)
{
- ei_assert(!(m_computeThinU || m_computeThinV) &&
+ eigen_assert(!(m_computeThinU || m_computeThinV) &&
"JacobiSVD: can't compute thin U or thin V with the FullPivHouseholderQR preconditioner. "
"Use the ColPivHouseholderQR preconditioner instead.");
}
@@ -460,85 +543,6 @@ void JacobiSVD<MatrixType, QRPreconditioner>::allocate(Index rows, Index cols, u
m_workMatrix.resize(m_diagSize, m_diagSize);
}
-
-template<typename MatrixType, int QRPreconditioner>
-struct ei_svd_precondition_2x2_block_to_be_real<MatrixType, QRPreconditioner, false>
-{
- typedef JacobiSVD<MatrixType, QRPreconditioner> SVD;
- typedef typename SVD::Index Index;
- static void run(typename SVD::WorkMatrixType&, SVD&, Index, Index) {}
-};
-
-template<typename MatrixType, int QRPreconditioner>
-struct ei_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;
- typedef typename SVD::Index Index;
- static void run(typename SVD::WorkMatrixType& work_matrix, SVD& svd, Index p, Index q)
- {
- Scalar z;
- JacobiRotation<Scalar> rot;
- RealScalar n = ei_sqrt(ei_abs2(work_matrix.coeff(p,p)) + ei_abs2(work_matrix.coeff(q,p)));
- if(n==0)
- {
- z = ei_abs(work_matrix.coeff(p,q)) / work_matrix.coeff(p,q);
- work_matrix.row(p) *= z;
- if(svd.computeU()) svd.m_matrixU.col(p) *= ei_conj(z);
- z = ei_abs(work_matrix.coeff(q,q)) / work_matrix.coeff(q,q);
- work_matrix.row(q) *= z;
- if(svd.computeU()) svd.m_matrixU.col(q) *= ei_conj(z);
- }
- else
- {
- rot.c() = ei_conj(work_matrix.coeff(p,p)) / n;
- 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))
- {
- Scalar z = ei_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))
- {
- z = ei_abs(work_matrix.coeff(q,q)) / work_matrix.coeff(q,q);
- work_matrix.row(q) *= z;
- if(svd.computeU()) svd.m_matrixU.col(q) *= ei_conj(z);
- }
- }
- }
-};
-
-template<typename MatrixType, typename RealScalar, typename Index>
-void ei_real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q,
- JacobiRotation<RealScalar> *j_left,
- JacobiRotation<RealScalar> *j_right)
-{
- Matrix<RealScalar,2,2> m;
- m << ei_real(matrix.coeff(p,p)), ei_real(matrix.coeff(p,q)),
- ei_real(matrix.coeff(q,p)), ei_real(matrix.coeff(q,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(t == RealScalar(0))
- {
- rot1.c() = 0;
- rot1.s() = d > 0 ? 1 : -1;
- }
- else
- {
- RealScalar u = d / t;
- rot1.c() = RealScalar(1) / ei_sqrt(1 + ei_abs2(u));
- rot1.s() = rot1.c() * u;
- }
- m.applyOnTheLeft(0,1,rot1);
- j_right->makeJacobi(m,0,1);
- *j_left = rot1 * j_right->transpose();
-}
-
template<typename MatrixType, int QRPreconditioner>
JacobiSVD<MatrixType, QRPreconditioner>&
JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsigned int computationOptions)
@@ -551,8 +555,8 @@ JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsig
/*** step 1. The R-SVD step: we use a QR decomposition to reduce to the case of a square matrix */
- if(!ei_qr_preconditioner_impl<MatrixType, QRPreconditioner, PreconditionIfMoreColsThanRows>::run(*this, matrix)
- && !ei_qr_preconditioner_impl<MatrixType, QRPreconditioner, PreconditionIfMoreRowsThanCols>::run(*this, matrix))
+ if(!internal::qr_preconditioner_impl<MatrixType, QRPreconditioner, internal::PreconditionIfMoreColsThanRows>::run(*this, matrix)
+ && !internal::qr_preconditioner_impl<MatrixType, QRPreconditioner, internal::PreconditionIfMoreRowsThanCols>::run(*this, matrix))
{
m_workMatrix = matrix.block(0,0,m_diagSize,m_diagSize);
if(m_computeFullU) m_matrixU.setIdentity(m_rows,m_rows);
@@ -577,15 +581,15 @@ 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.
- if(std::max(ei_abs(m_workMatrix.coeff(p,q)),ei_abs(m_workMatrix.coeff(q,p)))
- > std::max(ei_abs(m_workMatrix.coeff(p,p)),ei_abs(m_workMatrix.coeff(q,q)))*precision)
+ if(std::max(internal::abs(m_workMatrix.coeff(p,q)),internal::abs(m_workMatrix.coeff(q,p)))
+ > std::max(internal::abs(m_workMatrix.coeff(p,p)),internal::abs(m_workMatrix.coeff(q,q)))*precision)
{
finished = false;
// perform SVD decomposition of 2x2 sub-matrix corresponding to indices p,q to make it diagonal
- ei_svd_precondition_2x2_block_to_be_real<MatrixType, QRPreconditioner>::run(m_workMatrix, *this, p, q);
+ internal::svd_precondition_2x2_block_to_be_real<MatrixType, QRPreconditioner>::run(m_workMatrix, *this, p, q);
JacobiRotation<RealScalar> j_left, j_right;
- ei_real_2x2_jacobi_svd(m_workMatrix, p, q, &j_left, &j_right);
+ internal::real_2x2_jacobi_svd(m_workMatrix, p, q, &j_left, &j_right);
// accumulate resulting Jacobi rotations
m_workMatrix.applyOnTheLeft(p,q,j_left);
@@ -602,7 +606,7 @@ JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsig
for(Index i = 0; i < m_diagSize; ++i)
{
- RealScalar a = ei_abs(m_workMatrix.coeff(i,i));
+ RealScalar a = internal::abs(m_workMatrix.coeff(i,i));
m_singularValues.coeffRef(i) = a;
if(computeU() && (a!=RealScalar(0))) m_matrixU.col(i) *= m_workMatrix.coeff(i,i)/a;
}
@@ -632,16 +636,17 @@ JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsig
return *this;
}
+namespace internal {
template<typename _MatrixType, int QRPreconditioner, typename Rhs>
-struct ei_solve_retval<JacobiSVD<_MatrixType, QRPreconditioner>, Rhs>
- : ei_solve_retval_base<JacobiSVD<_MatrixType, QRPreconditioner>, Rhs>
+struct solve_retval<JacobiSVD<_MatrixType, QRPreconditioner>, Rhs>
+ : solve_retval_base<JacobiSVD<_MatrixType, QRPreconditioner>, Rhs>
{
typedef JacobiSVD<_MatrixType, QRPreconditioner> JacobiSVDType;
EIGEN_MAKE_SOLVE_HELPERS(JacobiSVDType,Rhs)
template<typename Dest> void evalTo(Dest& dst) const
{
- ei_assert(rhs().rows() == dec().rows());
+ eigen_assert(rhs().rows() == dec().rows());
// A = U S V^*
// So A^{-1} = V S^{-1} U^*
@@ -659,6 +664,7 @@ struct ei_solve_retval<JacobiSVD<_MatrixType, QRPreconditioner>, Rhs>
* rhs();
}
};
+} // end namespace internal
template<typename Derived>
JacobiSVD<typename MatrixBase<Derived>::PlainObject>