// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2008-2009 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 3 of the License, or (at your option) any later version. // // Alternatively, you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License and a copy of the GNU General Public License along with // Eigen. If not, see . #ifndef EIGEN_SVD_H #define EIGEN_SVD_H /** \ingroup SVD_Module * \nonstableyet * * \class SVD * * \brief Standard SVD decomposition of a matrix and associated features * * \param MatrixType the type of the matrix of which we are computing the SVD decomposition * * This class performs a standard SVD decomposition of a real matrix A of size \c M x \c N. * * \sa MatrixBase::SVD() */ template class SVD { private: typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; enum { PacketSize = ei_packet_traits::size, AlignmentMask = int(PacketSize)-1, MinSize = EIGEN_ENUM_MIN(MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime) }; typedef Matrix ColVector; typedef Matrix RowVector; typedef Matrix MatrixUType; typedef Matrix MatrixVType; typedef Matrix SingularValuesType; public: /** * \brief Default Constructor. * * The default constructor is useful in cases in which the user intends to * perform decompositions via SVD::compute(const MatrixType&). */ SVD() : m_matU(), m_matV(), m_sigma(), m_isInitialized(false) {} SVD(const MatrixType& matrix) : m_matU(matrix.rows(), matrix.rows()), m_matV(matrix.cols(),matrix.cols()), m_sigma(matrix.cols()), m_isInitialized(false) { compute(matrix); } template bool solve(const MatrixBase &b, ResultType* result) const; const MatrixUType& matrixU() const { ei_assert(m_isInitialized && "SVD is not initialized."); return m_matU; } const SingularValuesType& singularValues() const { ei_assert(m_isInitialized && "SVD is not initialized."); return m_sigma; } const MatrixVType& matrixV() const { ei_assert(m_isInitialized && "SVD is not initialized."); return m_matV; } void compute(const MatrixType& matrix); SVD& sort(); template void computeUnitaryPositive(UnitaryType *unitary, PositiveType *positive) const; template void computePositiveUnitary(PositiveType *positive, UnitaryType *unitary) const; template void computeRotationScaling(RotationType *unitary, ScalingType *positive) const; template void computeScalingRotation(ScalingType *positive, RotationType *unitary) const; protected: // Computes (a^2 + b^2)^(1/2) without destructive underflow or overflow. inline static Scalar pythag(Scalar a, Scalar b) { Scalar abs_a = ei_abs(a); Scalar abs_b = ei_abs(b); if (abs_a > abs_b) return abs_a*ei_sqrt(Scalar(1.0)+ei_abs2(abs_b/abs_a)); else return (abs_b == Scalar(0.0) ? Scalar(0.0) : abs_b*ei_sqrt(Scalar(1.0)+ei_abs2(abs_a/abs_b))); } inline static Scalar sign(Scalar a, Scalar b) { return (b >= Scalar(0.0) ? ei_abs(a) : -ei_abs(a)); } protected: /** \internal */ MatrixUType m_matU; /** \internal */ MatrixVType m_matV; /** \internal */ SingularValuesType m_sigma; bool m_isInitialized; }; /** Computes / recomputes the SVD decomposition A = U S V^* of \a matrix * * \note this code has been adapted from Numerical Recipes, third edition. */ template void SVD::compute(const MatrixType& matrix) { const int m = matrix.rows(); const int n = matrix.cols(); m_matU.resize(m, m); m_matU.setZero(); m_sigma.resize(n); m_matV.resize(n,n); int max_iters = 30; MatrixVType& V = m_matV; MatrixType A = matrix; SingularValuesType& W = m_sigma; bool flag; int i,its,j,jj,k,l,nm; Scalar anorm, c, f, g, h, s, scale, x, y, z; bool convergence = true; Scalar eps = precision(); Matrix rv1(n); g = scale = anorm = 0; // Householder reduction to bidiagonal form. for (i=0; i=0; i--) { //Accumulation of right-hand transformations. if (i < n-1) { if (g != Scalar(0.0)) { for (j=l; j=0; i--) { l = i+1; g = W[i]; if (n-l>0) A.row(i).end(n-l).setZero(); if (g != Scalar(0.0)) { g = Scalar(1.0)/g; for (j=l; j=0; k--) { for (its=0; its=0; l--) { // Test for splitting. nm = l-1; // Note that rv1[1] is always zero. //if ((double)(ei_abs(rv1[l])+anorm) == anorm) if (l==0 || ei_abs(rv1[l]) <= eps*anorm) { flag = false; break; } //if ((double)(ei_abs(W[nm])+anorm) == anorm) if (ei_abs(W[nm]) <= eps*anorm) break; } if (flag) { c = 0.0; //Cancellation of rv1[l], if l > 0. s = 1.0; for (i=l ;i=n) m_matU.block(0,0,m,n) = A; else m_matU = A.block(0,0,m,m); m_isInitialized = true; } template SVD& SVD::sort() { ei_assert(m_isInitialized && "SVD is not initialized."); int mu = m_matU.rows(); int mv = m_matV.rows(); int n = m_matU.cols(); for (int i=0; i p) { k = j; p = m_sigma.coeff(j); } } if (k != i) { m_sigma.coeffRef(k) = m_sigma.coeff(i); // i.e. m_sigma.coeffRef(i) = p; // swaps the i-th and the k-th elements int j = mu; for(int s=0; j!=0; ++s, --j) std::swap(m_matU.coeffRef(s,i), m_matU.coeffRef(s,k)); j = mv; for (int s=0; j!=0; ++s, --j) std::swap(m_matV.coeffRef(s,i), m_matV.coeffRef(s,k)); } } return *this; } /** \returns the solution of \f$ A x = b \f$ using the current SVD decomposition of A. * The parts of the solution corresponding to zero singular values are ignored. * * \sa MatrixBase::svd(), LU::solve(), LLT::solve() */ template template bool SVD::solve(const MatrixBase &b, ResultType* result) const { ei_assert(m_isInitialized && "SVD is not initialized."); const int rows = m_matU.rows(); ei_assert(b.rows() == rows); result->resize(m_matV.rows(), b.cols()); Scalar maxVal = m_sigma.cwise().abs().maxCoeff(); for (int j=0; j aux = m_matU.transpose() * b.col(j); for (int i = 0; i col(j) = m_matV * aux; } return true; } /** Computes the polar decomposition of the matrix, as a product unitary x positive. * * If either pointer is zero, the corresponding computation is skipped. * * Only for square matrices. * * \sa computePositiveUnitary(), computeRotationScaling() */ template template void SVD::computeUnitaryPositive(UnitaryType *unitary, PositiveType *positive) const { ei_assert(m_isInitialized && "SVD is not initialized."); ei_assert(m_matU.cols() == m_matV.cols() && "Polar decomposition is only for square matrices"); if(unitary) *unitary = m_matU * m_matV.adjoint(); if(positive) *positive = m_matV * m_sigma.asDiagonal() * m_matV.adjoint(); } /** Computes the polar decomposition of the matrix, as a product positive x unitary. * * If either pointer is zero, the corresponding computation is skipped. * * Only for square matrices. * * \sa computeUnitaryPositive(), computeRotationScaling() */ template template void SVD::computePositiveUnitary(UnitaryType *positive, PositiveType *unitary) const { ei_assert(m_isInitialized && "SVD is not initialized."); ei_assert(m_matU.rows() == m_matV.rows() && "Polar decomposition is only for square matrices"); if(unitary) *unitary = m_matU * m_matV.adjoint(); if(positive) *positive = m_matU * m_sigma.asDiagonal() * m_matU.adjoint(); } /** decomposes the matrix as a product rotation x scaling, the scaling being * not necessarily positive. * * If either pointer is zero, the corresponding computation is skipped. * * This method requires the Geometry module. * * \sa computeScalingRotation(), computeUnitaryPositive() */ template template void SVD::computeRotationScaling(RotationType *rotation, ScalingType *scaling) const { ei_assert(m_isInitialized && "SVD is not initialized."); ei_assert(m_matU.rows() == m_matV.rows() && "Polar decomposition is only for square matrices"); Scalar x = (m_matU * m_matV.adjoint()).determinant(); // so x has absolute value 1 Matrix sv(m_sigma); sv.coeffRef(0) *= x; if(scaling) scaling->lazyAssign(m_matV * sv.asDiagonal() * m_matV.adjoint()); if(rotation) { MatrixType m(m_matU); m.col(0) /= x; rotation->lazyAssign(m * m_matV.adjoint()); } } /** decomposes the matrix as a product scaling x rotation, the scaling being * not necessarily positive. * * If either pointer is zero, the corresponding computation is skipped. * * This method requires the Geometry module. * * \sa computeRotationScaling(), computeUnitaryPositive() */ template template void SVD::computeScalingRotation(ScalingType *scaling, RotationType *rotation) const { ei_assert(m_isInitialized && "SVD is not initialized."); ei_assert(m_matU.rows() == m_matV.rows() && "Polar decomposition is only for square matrices"); Scalar x = (m_matU * m_matV.adjoint()).determinant(); // so x has absolute value 1 Matrix sv(m_sigma); sv.coeffRef(0) *= x; if(scaling) scaling->lazyAssign(m_matU * sv.asDiagonal() * m_matU.adjoint()); if(rotation) { MatrixType m(m_matU); m.col(0) /= x; rotation->lazyAssign(m * m_matV.adjoint()); } } /** \svd_module * \returns the SVD decomposition of \c *this */ template inline SVD::PlainMatrixType> MatrixBase::svd() const { return SVD(derived()); } #endif // EIGEN_SVD_H