aboutsummaryrefslogtreecommitdiffhomepage
path: root/Eigen/src/SVD
diff options
context:
space:
mode:
authorGravatar Gael Guennebaud <g.gael@free.fr>2014-09-01 18:21:01 +0200
committerGravatar Gael Guennebaud <g.gael@free.fr>2014-09-01 18:21:01 +0200
commitb3a0365429345d37196a39a501ed071038031223 (patch)
tree17b01f0f705a65ba30af3467257abd619dd452a3 /Eigen/src/SVD
parent72c4f8ca8fc64a812801295babfb6d56ca96f427 (diff)
parenteb392960285c2645d45118d424786a73768ff50a (diff)
merge with default branch
Diffstat (limited to 'Eigen/src/SVD')
-rw-r--r--Eigen/src/SVD/JacobiSVD.h185
-rw-r--r--Eigen/src/SVD/SVDBase.h263
-rw-r--r--Eigen/src/SVD/UpperBidiagonalization.h1
3 files changed, 298 insertions, 151 deletions
diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h
index d1b63b607..3d778516a 100644
--- a/Eigen/src/SVD/JacobiSVD.h
+++ b/Eigen/src/SVD/JacobiSVD.h
@@ -2,6 +2,7 @@
// for linear algebra.
//
// Copyright (C) 2009-2010 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2013-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
@@ -442,6 +443,12 @@ void real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q,
*j_left = rot1 * j_right->transpose();
}
+template<typename _MatrixType, int QRPreconditioner>
+struct traits<JacobiSVD<_MatrixType,QRPreconditioner> >
+{
+ typedef _MatrixType MatrixType;
+};
+
} // end namespace internal
/** \ingroup SVD_Module
@@ -498,7 +505,9 @@ void real_2x2_jacobi_svd(const MatrixType& matrix, Index p, Index q,
* \sa MatrixBase::jacobiSvd()
*/
template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
+ : public SVDBase<JacobiSVD<_MatrixType,QRPreconditioner> >
{
+ typedef SVDBase<JacobiSVD> Base;
public:
typedef _MatrixType MatrixType;
@@ -515,13 +524,10 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
MatrixOptions = MatrixType::Options
};
- typedef Matrix<Scalar, RowsAtCompileTime, RowsAtCompileTime,
- MatrixOptions, MaxRowsAtCompileTime, MaxRowsAtCompileTime>
- MatrixUType;
- typedef Matrix<Scalar, ColsAtCompileTime, ColsAtCompileTime,
- MatrixOptions, MaxColsAtCompileTime, MaxColsAtCompileTime>
- MatrixVType;
- typedef typename internal::plain_diag_type<MatrixType, RealScalar>::type SingularValuesType;
+ typedef typename Base::MatrixUType MatrixUType;
+ typedef typename Base::MatrixVType MatrixVType;
+ typedef typename Base::SingularValuesType SingularValuesType;
+
typedef typename internal::plain_row_type<MatrixType>::type RowType;
typedef typename internal::plain_col_type<MatrixType>::type ColType;
typedef Matrix<Scalar, DiagSizeAtCompileTime, DiagSizeAtCompileTime,
@@ -534,11 +540,6 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
* perform decompositions via JacobiSVD::compute(const MatrixType&).
*/
JacobiSVD()
- : m_isInitialized(false),
- m_isAllocated(false),
- m_usePrescribedThreshold(false),
- m_computationOptions(0),
- m_rows(-1), m_cols(-1), m_diagSize(0)
{}
@@ -549,11 +550,6 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
* \sa JacobiSVD()
*/
JacobiSVD(Index rows, Index cols, unsigned int computationOptions = 0)
- : m_isInitialized(false),
- m_isAllocated(false),
- m_usePrescribedThreshold(false),
- m_computationOptions(0),
- m_rows(-1), m_cols(-1)
{
allocate(rows, cols, computationOptions);
}
@@ -569,11 +565,6 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
* available with the (non-default) FullPivHouseholderQR preconditioner.
*/
JacobiSVD(const MatrixType& matrix, unsigned int computationOptions = 0)
- : m_isInitialized(false),
- m_isAllocated(false),
- m_usePrescribedThreshold(false),
- m_computationOptions(0),
- m_rows(-1), m_cols(-1)
{
compute(matrix, computationOptions);
}
@@ -601,54 +592,6 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
return compute(matrix, m_computationOptions);
}
- /** \returns the \a U matrix.
- *
- * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p,
- * the U matrix is n-by-n if you asked for #ComputeFullU, and is n-by-m if you asked for #ComputeThinU.
- *
- * The \a m first columns of \a U are the left singular vectors of the matrix being decomposed.
- *
- * This method asserts that you asked for \a U to be computed.
- */
- const MatrixUType& matrixU() const
- {
- 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;
- }
-
- /** \returns the \a V matrix.
- *
- * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p,
- * the V matrix is p-by-p if you asked for #ComputeFullV, and is p-by-m if you asked for ComputeThinV.
- *
- * The \a m first columns of \a V are the right singular vectors of the matrix being decomposed.
- *
- * This method asserts that you asked for \a V to be computed.
- */
- const MatrixVType& matrixV() const
- {
- 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;
- }
-
- /** \returns the vector of singular values.
- *
- * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p, the
- * returned vector has size \a m. Singular values are always sorted in decreasing order.
- */
- const SingularValuesType& singularValues() const
- {
- eigen_assert(m_isInitialized && "JacobiSVD is not initialized.");
- return m_singularValues;
- }
-
- /** \returns true if \a U (full or thin) is asked for in this SVD decomposition */
- inline bool computeU() const { return m_computeFullU || m_computeThinU; }
- /** \returns true if \a V (full or thin) is asked for in this SVD decomposition */
- inline bool computeV() const { return m_computeFullV || m_computeThinV; }
-
/** \returns a (least squares) solution of \f$ A x = b \f$ using the current SVD decomposition of A.
*
* \param b the right-hand-side of the equation to solve.
@@ -677,80 +620,13 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
return internal::solve_retval<JacobiSVD, Rhs>(*this, b.derived());
}
#endif
-
- /** \returns the number of singular values that are not exactly 0 */
- Index nonzeroSingularValues() const
- {
- eigen_assert(m_isInitialized && "JacobiSVD is not initialized.");
- return m_nonzeroSingularValues;
- }
-
- /** \returns the rank of the matrix of which \c *this is the SVD.
- *
- * \note This method has to determine which singular values should be considered nonzero.
- * For that, it uses the threshold value that you can control by calling
- * setThreshold(const RealScalar&).
- */
- inline Index rank() const
- {
- using std::abs;
- eigen_assert(m_isInitialized && "JacobiSVD is not initialized.");
- if(m_singularValues.size()==0) return 0;
- RealScalar premultiplied_threshold = m_singularValues.coeff(0) * threshold();
- Index i = m_nonzeroSingularValues-1;
- while(i>=0 && m_singularValues.coeff(i) < premultiplied_threshold) --i;
- return i+1;
- }
- /** Allows to prescribe a threshold to be used by certain methods, such as rank() and solve(),
- * which need to determine when singular values are to be considered nonzero.
- * This is not used for the SVD decomposition itself.
- *
- * When it needs to get the threshold value, Eigen calls threshold().
- * The default is \c NumTraits<Scalar>::epsilon()
- *
- * \param threshold The new value to use as the threshold.
- *
- * A singular value will be considered nonzero if its value is strictly greater than
- * \f$ \vert singular value \vert \leqslant threshold \times \vert max singular value \vert \f$.
- *
- * If you want to come back to the default behavior, call setThreshold(Default_t)
- */
- JacobiSVD& setThreshold(const RealScalar& threshold)
- {
- m_usePrescribedThreshold = true;
- m_prescribedThreshold = threshold;
- return *this;
- }
-
- /** Allows to come back to the default behavior, letting Eigen use its default formula for
- * determining the threshold.
- *
- * You should pass the special object Eigen::Default as parameter here.
- * \code svd.setThreshold(Eigen::Default); \endcode
- *
- * See the documentation of setThreshold(const RealScalar&).
- */
- JacobiSVD& setThreshold(Default_t)
- {
- m_usePrescribedThreshold = false;
- return *this;
- }
+ using Base::computeU;
+ using Base::computeV;
+ using Base::rows;
+ using Base::cols;
+ using Base::rank;
- /** Returns the threshold that will be used by certain methods such as rank().
- *
- * See the documentation of setThreshold(const RealScalar&).
- */
- RealScalar threshold() const
- {
- eigen_assert(m_isInitialized || m_usePrescribedThreshold);
- return m_usePrescribedThreshold ? m_prescribedThreshold
- : (std::max<Index>)(1,m_diagSize)*NumTraits<Scalar>::epsilon();
- }
-
- inline Index rows() const { return m_rows; }
- inline Index cols() const { return m_cols; }
-
#ifndef EIGEN_PARSED_BY_DOXYGEN
template<typename RhsType, typename DstType>
EIGEN_DEVICE_FUNC
@@ -761,16 +637,23 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
void allocate(Index rows, Index cols, unsigned int computationOptions);
protected:
- MatrixUType m_matrixU;
- MatrixVType m_matrixV;
- SingularValuesType m_singularValues;
+ using Base::m_matrixU;
+ using Base::m_matrixV;
+ using Base::m_singularValues;
+ using Base::m_isInitialized;
+ using Base::m_isAllocated;
+ using Base::m_usePrescribedThreshold;
+ using Base::m_computeFullU;
+ using Base::m_computeThinU;
+ using Base::m_computeFullV;
+ using Base::m_computeThinV;
+ using Base::m_computationOptions;
+ using Base::m_nonzeroSingularValues;
+ using Base::m_rows;
+ using Base::m_cols;
+ using Base::m_diagSize;
+ using Base::m_prescribedThreshold;
WorkMatrixType m_workMatrix;
- bool m_isInitialized, m_isAllocated, m_usePrescribedThreshold;
- bool m_computeFullU, m_computeThinU;
- bool m_computeFullV, m_computeThinV;
- unsigned int m_computationOptions;
- Index m_nonzeroSingularValues, m_rows, m_cols, m_diagSize;
- RealScalar m_prescribedThreshold;
template<typename __MatrixType, int _QRPreconditioner, bool _IsComplex>
friend struct internal::svd_precondition_2x2_block_to_be_real;
diff --git a/Eigen/src/SVD/SVDBase.h b/Eigen/src/SVD/SVDBase.h
new file mode 100644
index 000000000..61b01fb8a
--- /dev/null
+++ b/Eigen/src/SVD/SVDBase.h
@@ -0,0 +1,263 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2009-2010 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2014 Gael Guennebaud <gael.guennebaud@inria.fr>
+//
+// Copyright (C) 2013 Gauthier Brun <brun.gauthier@gmail.com>
+// Copyright (C) 2013 Nicolas Carre <nicolas.carre@ensimag.fr>
+// Copyright (C) 2013 Jean Ceccato <jean.ceccato@ensimag.fr>
+// Copyright (C) 2013 Pierre Zoppitelli <pierre.zoppitelli@ensimag.fr>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef EIGEN_SVDBASE_H
+#define EIGEN_SVDBASE_H
+
+namespace Eigen {
+/** \ingroup SVD_Module
+ *
+ *
+ * \class SVDBase
+ *
+ * \brief Base class of SVD algorithms
+ *
+ * \tparam Derived the type of the actual SVD decomposition
+ *
+ * SVD decomposition consists in decomposing any n-by-p matrix \a A as a product
+ * \f[ A = U S V^* \f]
+ * where \a U is a n-by-n unitary, \a V is a p-by-p unitary, and \a S is a n-by-p real positive matrix which is zero outside of its main diagonal;
+ * the diagonal entries of S are known as the \em singular \em values of \a A and the columns of \a U and \a V are known as the left
+ * and right \em singular \em vectors of \a A respectively.
+ *
+ * Singular values are always sorted in decreasing order.
+ *
+ *
+ * You can ask for only \em thin \a U or \a V to be computed, meaning the following. In case of a rectangular n-by-p matrix, letting \a m be the
+ * smaller value among \a n and \a p, there are only \a m singular vectors; the remaining columns of \a U and \a V do not correspond to actual
+ * singular vectors. Asking for \em thin \a U or \a V means asking for only their \a m first columns to be formed. So \a U is then a n-by-m matrix,
+ * and \a V is then a p-by-m matrix. Notice that thin \a U and \a V are all you need for (least squares) solving.
+ *
+ * If the input matrix has inf or nan coefficients, the result of the computation is undefined, but the computation is guaranteed to
+ * terminate in finite (and reasonable) time.
+ * \sa MatrixBase::genericSvd()
+ */
+template<typename Derived>
+class SVDBase
+{
+
+public:
+ typedef typename internal::traits<Derived>::MatrixType MatrixType;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
+ typedef typename MatrixType::Index Index;
+ enum {
+ RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+ ColsAtCompileTime = MatrixType::ColsAtCompileTime,
+ DiagSizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_DYNAMIC(RowsAtCompileTime,ColsAtCompileTime),
+ MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
+ MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
+ MaxDiagSizeAtCompileTime = EIGEN_SIZE_MIN_PREFER_FIXED(MaxRowsAtCompileTime,MaxColsAtCompileTime),
+ MatrixOptions = MatrixType::Options
+ };
+
+ typedef Matrix<Scalar, RowsAtCompileTime, RowsAtCompileTime, MatrixOptions, MaxRowsAtCompileTime, MaxRowsAtCompileTime> MatrixUType;
+ typedef Matrix<Scalar, ColsAtCompileTime, ColsAtCompileTime, MatrixOptions, MaxColsAtCompileTime, MaxColsAtCompileTime> MatrixVType;
+ typedef typename internal::plain_diag_type<MatrixType, RealScalar>::type SingularValuesType;
+
+ Derived& derived() { return *static_cast<Derived*>(this); }
+ const Derived& derived() const { return *static_cast<const Derived*>(this); }
+
+ /** \returns the \a U matrix.
+ *
+ * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p,
+ * the U matrix is n-by-n if you asked for #ComputeFullU, and is n-by-m if you asked for #ComputeThinU.
+ *
+ * The \a m first columns of \a U are the left singular vectors of the matrix being decomposed.
+ *
+ * This method asserts that you asked for \a U to be computed.
+ */
+ const MatrixUType& matrixU() const
+ {
+ eigen_assert(m_isInitialized && "SVD is not initialized.");
+ eigen_assert(computeU() && "This SVD decomposition didn't compute U. Did you ask for it?");
+ return m_matrixU;
+ }
+
+ /** \returns the \a V matrix.
+ *
+ * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p,
+ * the V matrix is p-by-p if you asked for #ComputeFullV, and is p-by-m if you asked for ComputeThinV.
+ *
+ * The \a m first columns of \a V are the right singular vectors of the matrix being decomposed.
+ *
+ * This method asserts that you asked for \a V to be computed.
+ */
+ const MatrixVType& matrixV() const
+ {
+ eigen_assert(m_isInitialized && "SVD is not initialized.");
+ eigen_assert(computeV() && "This SVD decomposition didn't compute V. Did you ask for it?");
+ return m_matrixV;
+ }
+
+ /** \returns the vector of singular values.
+ *
+ * For the SVD decomposition of a n-by-p matrix, letting \a m be the minimum of \a n and \a p, the
+ * returned vector has size \a m. Singular values are always sorted in decreasing order.
+ */
+ const SingularValuesType& singularValues() const
+ {
+ eigen_assert(m_isInitialized && "SVD is not initialized.");
+ return m_singularValues;
+ }
+
+ /** \returns the number of singular values that are not exactly 0 */
+ Index nonzeroSingularValues() const
+ {
+ eigen_assert(m_isInitialized && "SVD is not initialized.");
+ return m_nonzeroSingularValues;
+ }
+
+ /** \returns the rank of the matrix of which \c *this is the SVD.
+ *
+ * \note This method has to determine which singular values should be considered nonzero.
+ * For that, it uses the threshold value that you can control by calling
+ * setThreshold(const RealScalar&).
+ */
+ inline Index rank() const
+ {
+ using std::abs;
+ eigen_assert(m_isInitialized && "JacobiSVD is not initialized.");
+ if(m_singularValues.size()==0) return 0;
+ RealScalar premultiplied_threshold = m_singularValues.coeff(0) * threshold();
+ Index i = m_nonzeroSingularValues-1;
+ while(i>=0 && m_singularValues.coeff(i) < premultiplied_threshold) --i;
+ return i+1;
+ }
+
+ /** Allows to prescribe a threshold to be used by certain methods, such as rank() and solve(),
+ * which need to determine when singular values are to be considered nonzero.
+ * This is not used for the SVD decomposition itself.
+ *
+ * When it needs to get the threshold value, Eigen calls threshold().
+ * The default is \c NumTraits<Scalar>::epsilon()
+ *
+ * \param threshold The new value to use as the threshold.
+ *
+ * A singular value will be considered nonzero if its value is strictly greater than
+ * \f$ \vert singular value \vert \leqslant threshold \times \vert max singular value \vert \f$.
+ *
+ * If you want to come back to the default behavior, call setThreshold(Default_t)
+ */
+ Derived& setThreshold(const RealScalar& threshold)
+ {
+ m_usePrescribedThreshold = true;
+ m_prescribedThreshold = threshold;
+ return derived();
+ }
+
+ /** Allows to come back to the default behavior, letting Eigen use its default formula for
+ * determining the threshold.
+ *
+ * You should pass the special object Eigen::Default as parameter here.
+ * \code svd.setThreshold(Eigen::Default); \endcode
+ *
+ * See the documentation of setThreshold(const RealScalar&).
+ */
+ Derived& setThreshold(Default_t)
+ {
+ m_usePrescribedThreshold = false;
+ return derived();
+ }
+
+ /** Returns the threshold that will be used by certain methods such as rank().
+ *
+ * See the documentation of setThreshold(const RealScalar&).
+ */
+ RealScalar threshold() const
+ {
+ eigen_assert(m_isInitialized || m_usePrescribedThreshold);
+ return m_usePrescribedThreshold ? m_prescribedThreshold
+ : (std::max<Index>)(1,m_diagSize)*NumTraits<Scalar>::epsilon();
+ }
+
+ /** \returns true if \a U (full or thin) is asked for in this SVD decomposition */
+ inline bool computeU() const { return m_computeFullU || m_computeThinU; }
+ /** \returns true if \a V (full or thin) is asked for in this SVD decomposition */
+ inline bool computeV() const { return m_computeFullV || m_computeThinV; }
+
+ inline Index rows() const { return m_rows; }
+ inline Index cols() const { return m_cols; }
+
+protected:
+ // return true if already allocated
+ bool allocate(Index rows, Index cols, unsigned int computationOptions) ;
+
+ MatrixUType m_matrixU;
+ MatrixVType m_matrixV;
+ SingularValuesType m_singularValues;
+ bool m_isInitialized, m_isAllocated, m_usePrescribedThreshold;
+ bool m_computeFullU, m_computeThinU;
+ bool m_computeFullV, m_computeThinV;
+ unsigned int m_computationOptions;
+ Index m_nonzeroSingularValues, m_rows, m_cols, m_diagSize;
+ RealScalar m_prescribedThreshold;
+
+ /** \brief Default Constructor.
+ *
+ * Default constructor of SVDBase
+ */
+ SVDBase()
+ : m_isInitialized(false),
+ m_isAllocated(false),
+ m_usePrescribedThreshold(false),
+ m_computationOptions(0),
+ m_rows(-1), m_cols(-1), m_diagSize(0)
+ {}
+
+
+};
+
+
+template<typename MatrixType>
+bool SVDBase<MatrixType>::allocate(Index rows, Index cols, unsigned int computationOptions)
+{
+ eigen_assert(rows >= 0 && cols >= 0);
+
+ if (m_isAllocated &&
+ rows == m_rows &&
+ cols == m_cols &&
+ computationOptions == m_computationOptions)
+ {
+ return true;
+ }
+
+ m_rows = rows;
+ m_cols = cols;
+ m_isInitialized = false;
+ m_isAllocated = true;
+ m_computationOptions = computationOptions;
+ m_computeFullU = (computationOptions & ComputeFullU) != 0;
+ m_computeThinU = (computationOptions & ComputeThinU) != 0;
+ m_computeFullV = (computationOptions & ComputeFullV) != 0;
+ m_computeThinV = (computationOptions & ComputeThinV) != 0;
+ eigen_assert(!(m_computeFullU && m_computeThinU) && "SVDBase: you can't ask for both full and thin U");
+ eigen_assert(!(m_computeFullV && m_computeThinV) && "SVDBase: you can't ask for both full and thin V");
+ eigen_assert(EIGEN_IMPLIES(m_computeThinU || m_computeThinV, MatrixType::ColsAtCompileTime==Dynamic) &&
+ "SVDBase: thin U and V are only available when your matrix has a dynamic number of columns.");
+
+ m_diagSize = (std::min)(m_rows, m_cols);
+ m_singularValues.resize(m_diagSize);
+ if(RowsAtCompileTime==Dynamic)
+ m_matrixU.resize(m_rows, m_computeFullU ? m_rows : m_computeThinU ? m_diagSize : 0);
+ if(ColsAtCompileTime==Dynamic)
+ m_matrixV.resize(m_cols, m_computeFullV ? m_cols : m_computeThinV ? m_diagSize : 0);
+
+ return false;
+}
+
+}// end namespace
+
+#endif // EIGEN_SVDBASE_H
diff --git a/Eigen/src/SVD/UpperBidiagonalization.h b/Eigen/src/SVD/UpperBidiagonalization.h
index 40067682c..225b19e3c 100644
--- a/Eigen/src/SVD/UpperBidiagonalization.h
+++ b/Eigen/src/SVD/UpperBidiagonalization.h
@@ -2,6 +2,7 @@
// for linear algebra.
//
// Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@gmail.com>
+// Copyright (C) 2013-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed