Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/eigen3/Eigen/src/SVD/UpperBidiagonalization.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 // This file is part of Eigen, a lightweight C++ template library
0002 // for linear algebra.
0003 //
0004 // Copyright (C) 2010 Benoit Jacob <jacob.benoit.1@gmail.com>
0005 // Copyright (C) 2013-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
0006 //
0007 // This Source Code Form is subject to the terms of the Mozilla
0008 // Public License v. 2.0. If a copy of the MPL was not distributed
0009 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
0010 
0011 #ifndef EIGEN_BIDIAGONALIZATION_H
0012 #define EIGEN_BIDIAGONALIZATION_H
0013 
0014 namespace Eigen { 
0015 
0016 namespace internal {
0017 // UpperBidiagonalization will probably be replaced by a Bidiagonalization class, don't want to make it stable API.
0018 // At the same time, it's useful to keep for now as it's about the only thing that is testing the BandMatrix class.
0019 
0020 template<typename _MatrixType> class UpperBidiagonalization
0021 {
0022   public:
0023 
0024     typedef _MatrixType MatrixType;
0025     enum {
0026       RowsAtCompileTime = MatrixType::RowsAtCompileTime,
0027       ColsAtCompileTime = MatrixType::ColsAtCompileTime,
0028       ColsAtCompileTimeMinusOne = internal::decrement_size<ColsAtCompileTime>::ret
0029     };
0030     typedef typename MatrixType::Scalar Scalar;
0031     typedef typename MatrixType::RealScalar RealScalar;
0032     typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3
0033     typedef Matrix<Scalar, 1, ColsAtCompileTime> RowVectorType;
0034     typedef Matrix<Scalar, RowsAtCompileTime, 1> ColVectorType;
0035     typedef BandMatrix<RealScalar, ColsAtCompileTime, ColsAtCompileTime, 1, 0, RowMajor> BidiagonalType;
0036     typedef Matrix<Scalar, ColsAtCompileTime, 1> DiagVectorType;
0037     typedef Matrix<Scalar, ColsAtCompileTimeMinusOne, 1> SuperDiagVectorType;
0038     typedef HouseholderSequence<
0039               const MatrixType,
0040               const typename internal::remove_all<typename Diagonal<const MatrixType,0>::ConjugateReturnType>::type
0041             > HouseholderUSequenceType;
0042     typedef HouseholderSequence<
0043               const typename internal::remove_all<typename MatrixType::ConjugateReturnType>::type,
0044               Diagonal<const MatrixType,1>,
0045               OnTheRight
0046             > HouseholderVSequenceType;
0047     
0048     /**
0049     * \brief Default Constructor.
0050     *
0051     * The default constructor is useful in cases in which the user intends to
0052     * perform decompositions via Bidiagonalization::compute(const MatrixType&).
0053     */
0054     UpperBidiagonalization() : m_householder(), m_bidiagonal(), m_isInitialized(false) {}
0055 
0056     explicit UpperBidiagonalization(const MatrixType& matrix)
0057       : m_householder(matrix.rows(), matrix.cols()),
0058         m_bidiagonal(matrix.cols(), matrix.cols()),
0059         m_isInitialized(false)
0060     {
0061       compute(matrix);
0062     }
0063     
0064     UpperBidiagonalization& compute(const MatrixType& matrix);
0065     UpperBidiagonalization& computeUnblocked(const MatrixType& matrix);
0066     
0067     const MatrixType& householder() const { return m_householder; }
0068     const BidiagonalType& bidiagonal() const { return m_bidiagonal; }
0069     
0070     const HouseholderUSequenceType householderU() const
0071     {
0072       eigen_assert(m_isInitialized && "UpperBidiagonalization is not initialized.");
0073       return HouseholderUSequenceType(m_householder, m_householder.diagonal().conjugate());
0074     }
0075 
0076     const HouseholderVSequenceType householderV() // const here gives nasty errors and i'm lazy
0077     {
0078       eigen_assert(m_isInitialized && "UpperBidiagonalization is not initialized.");
0079       return HouseholderVSequenceType(m_householder.conjugate(), m_householder.const_derived().template diagonal<1>())
0080              .setLength(m_householder.cols()-1)
0081              .setShift(1);
0082     }
0083     
0084   protected:
0085     MatrixType m_householder;
0086     BidiagonalType m_bidiagonal;
0087     bool m_isInitialized;
0088 };
0089 
0090 // Standard upper bidiagonalization without fancy optimizations
0091 // This version should be faster for small matrix size
0092 template<typename MatrixType>
0093 void upperbidiagonalization_inplace_unblocked(MatrixType& mat,
0094                                               typename MatrixType::RealScalar *diagonal,
0095                                               typename MatrixType::RealScalar *upper_diagonal,
0096                                               typename MatrixType::Scalar* tempData = 0)
0097 {
0098   typedef typename MatrixType::Scalar Scalar;
0099 
0100   Index rows = mat.rows();
0101   Index cols = mat.cols();
0102 
0103   typedef Matrix<Scalar,Dynamic,1,ColMajor,MatrixType::MaxRowsAtCompileTime,1> TempType;
0104   TempType tempVector;
0105   if(tempData==0)
0106   {
0107     tempVector.resize(rows);
0108     tempData = tempVector.data();
0109   }
0110 
0111   for (Index k = 0; /* breaks at k==cols-1 below */ ; ++k)
0112   {
0113     Index remainingRows = rows - k;
0114     Index remainingCols = cols - k - 1;
0115 
0116     // construct left householder transform in-place in A
0117     mat.col(k).tail(remainingRows)
0118        .makeHouseholderInPlace(mat.coeffRef(k,k), diagonal[k]);
0119     // apply householder transform to remaining part of A on the left
0120     mat.bottomRightCorner(remainingRows, remainingCols)
0121        .applyHouseholderOnTheLeft(mat.col(k).tail(remainingRows-1), mat.coeff(k,k), tempData);
0122 
0123     if(k == cols-1) break;
0124 
0125     // construct right householder transform in-place in mat
0126     mat.row(k).tail(remainingCols)
0127        .makeHouseholderInPlace(mat.coeffRef(k,k+1), upper_diagonal[k]);
0128     // apply householder transform to remaining part of mat on the left
0129     mat.bottomRightCorner(remainingRows-1, remainingCols)
0130        .applyHouseholderOnTheRight(mat.row(k).tail(remainingCols-1).adjoint(), mat.coeff(k,k+1), tempData);
0131   }
0132 }
0133 
0134 /** \internal
0135   * Helper routine for the block reduction to upper bidiagonal form.
0136   *
0137   * Let's partition the matrix A:
0138   * 
0139   *      | A00 A01 |
0140   *  A = |         |
0141   *      | A10 A11 |
0142   *
0143   * This function reduces to bidiagonal form the left \c rows x \a blockSize vertical panel [A00/A10]
0144   * and the \a blockSize x \c cols horizontal panel [A00 A01] of the matrix \a A. The bottom-right block A11
0145   * is updated using matrix-matrix products:
0146   *   A22 -= V * Y^T - X * U^T
0147   * where V and U contains the left and right Householder vectors. U and V are stored in A10, and A01
0148   * respectively, and the update matrices X and Y are computed during the reduction.
0149   * 
0150   */
0151 template<typename MatrixType>
0152 void upperbidiagonalization_blocked_helper(MatrixType& A,
0153                                            typename MatrixType::RealScalar *diagonal,
0154                                            typename MatrixType::RealScalar *upper_diagonal,
0155                                            Index bs,
0156                                            Ref<Matrix<typename MatrixType::Scalar, Dynamic, Dynamic,
0157                                                       traits<MatrixType>::Flags & RowMajorBit> > X,
0158                                            Ref<Matrix<typename MatrixType::Scalar, Dynamic, Dynamic,
0159                                                       traits<MatrixType>::Flags & RowMajorBit> > Y)
0160 {
0161   typedef typename MatrixType::Scalar Scalar;
0162   typedef typename MatrixType::RealScalar RealScalar;
0163   typedef typename NumTraits<RealScalar>::Literal Literal;
0164   enum { StorageOrder = traits<MatrixType>::Flags & RowMajorBit };
0165   typedef InnerStride<int(StorageOrder) == int(ColMajor) ? 1 : Dynamic> ColInnerStride;
0166   typedef InnerStride<int(StorageOrder) == int(ColMajor) ? Dynamic : 1> RowInnerStride;
0167   typedef Ref<Matrix<Scalar, Dynamic, 1>, 0, ColInnerStride>    SubColumnType;
0168   typedef Ref<Matrix<Scalar, 1, Dynamic>, 0, RowInnerStride>    SubRowType;
0169   typedef Ref<Matrix<Scalar, Dynamic, Dynamic, StorageOrder > > SubMatType;
0170   
0171   Index brows = A.rows();
0172   Index bcols = A.cols();
0173 
0174   Scalar tau_u, tau_u_prev(0), tau_v;
0175 
0176   for(Index k = 0; k < bs; ++k)
0177   {
0178     Index remainingRows = brows - k;
0179     Index remainingCols = bcols - k - 1;
0180 
0181     SubMatType X_k1( X.block(k,0, remainingRows,k) );
0182     SubMatType V_k1( A.block(k,0, remainingRows,k) );
0183 
0184     // 1 - update the k-th column of A
0185     SubColumnType v_k = A.col(k).tail(remainingRows);
0186           v_k -= V_k1 * Y.row(k).head(k).adjoint();
0187     if(k) v_k -= X_k1 * A.col(k).head(k);
0188     
0189     // 2 - construct left Householder transform in-place
0190     v_k.makeHouseholderInPlace(tau_v, diagonal[k]);
0191        
0192     if(k+1<bcols)
0193     {
0194       SubMatType Y_k  ( Y.block(k+1,0, remainingCols, k+1) );
0195       SubMatType U_k1 ( A.block(0,k+1, k,remainingCols) );
0196       
0197       // this eases the application of Householder transforAions
0198       // A(k,k) will store tau_v later
0199       A(k,k) = Scalar(1);
0200 
0201       // 3 - Compute y_k^T = tau_v * ( A^T*v_k - Y_k-1*V_k-1^T*v_k - U_k-1*X_k-1^T*v_k )
0202       {
0203         SubColumnType y_k( Y.col(k).tail(remainingCols) );
0204         
0205         // let's use the beginning of column k of Y as a temporary vector
0206         SubColumnType tmp( Y.col(k).head(k) );
0207         y_k.noalias()  = A.block(k,k+1, remainingRows,remainingCols).adjoint() * v_k; // bottleneck
0208         tmp.noalias()  = V_k1.adjoint()  * v_k;
0209         y_k.noalias() -= Y_k.leftCols(k) * tmp;
0210         tmp.noalias()  = X_k1.adjoint()  * v_k;
0211         y_k.noalias() -= U_k1.adjoint()  * tmp;
0212         y_k *= numext::conj(tau_v);
0213       }
0214 
0215       // 4 - update k-th row of A (it will become u_k)
0216       SubRowType u_k( A.row(k).tail(remainingCols) );
0217       u_k = u_k.conjugate();
0218       {
0219         u_k -= Y_k * A.row(k).head(k+1).adjoint();
0220         if(k) u_k -= U_k1.adjoint() * X.row(k).head(k).adjoint();
0221       }
0222 
0223       // 5 - construct right Householder transform in-place
0224       u_k.makeHouseholderInPlace(tau_u, upper_diagonal[k]);
0225 
0226       // this eases the application of Householder transformations
0227       // A(k,k+1) will store tau_u later
0228       A(k,k+1) = Scalar(1);
0229 
0230       // 6 - Compute x_k = tau_u * ( A*u_k - X_k-1*U_k-1^T*u_k - V_k*Y_k^T*u_k )
0231       {
0232         SubColumnType x_k ( X.col(k).tail(remainingRows-1) );
0233         
0234         // let's use the beginning of column k of X as a temporary vectors
0235         // note that tmp0 and tmp1 overlaps
0236         SubColumnType tmp0 ( X.col(k).head(k) ),
0237                       tmp1 ( X.col(k).head(k+1) );
0238                     
0239         x_k.noalias()   = A.block(k+1,k+1, remainingRows-1,remainingCols) * u_k.transpose(); // bottleneck
0240         tmp0.noalias()  = U_k1 * u_k.transpose();
0241         x_k.noalias()  -= X_k1.bottomRows(remainingRows-1) * tmp0;
0242         tmp1.noalias()  = Y_k.adjoint() * u_k.transpose();
0243         x_k.noalias()  -= A.block(k+1,0, remainingRows-1,k+1) * tmp1;
0244         x_k *= numext::conj(tau_u);
0245         tau_u = numext::conj(tau_u);
0246         u_k = u_k.conjugate();
0247       }
0248 
0249       if(k>0) A.coeffRef(k-1,k) = tau_u_prev;
0250       tau_u_prev = tau_u;
0251     }
0252     else
0253       A.coeffRef(k-1,k) = tau_u_prev;
0254 
0255     A.coeffRef(k,k) = tau_v;
0256   }
0257   
0258   if(bs<bcols)
0259     A.coeffRef(bs-1,bs) = tau_u_prev;
0260 
0261   // update A22
0262   if(bcols>bs && brows>bs)
0263   {
0264     SubMatType A11( A.bottomRightCorner(brows-bs,bcols-bs) );
0265     SubMatType A10( A.block(bs,0, brows-bs,bs) );
0266     SubMatType A01( A.block(0,bs, bs,bcols-bs) );
0267     Scalar tmp = A01(bs-1,0);
0268     A01(bs-1,0) = Literal(1);
0269     A11.noalias() -= A10 * Y.topLeftCorner(bcols,bs).bottomRows(bcols-bs).adjoint();
0270     A11.noalias() -= X.topLeftCorner(brows,bs).bottomRows(brows-bs) * A01;
0271     A01(bs-1,0) = tmp;
0272   }
0273 }
0274 
0275 /** \internal
0276   *
0277   * Implementation of a block-bidiagonal reduction.
0278   * It is based on the following paper:
0279   *   The Design of a Parallel Dense Linear Algebra Software Library: Reduction to Hessenberg, Tridiagonal, and Bidiagonal Form.
0280   *   by Jaeyoung Choi, Jack J. Dongarra, David W. Walker. (1995)
0281   *   section 3.3
0282   */
0283 template<typename MatrixType, typename BidiagType>
0284 void upperbidiagonalization_inplace_blocked(MatrixType& A, BidiagType& bidiagonal,
0285                                             Index maxBlockSize=32,
0286                                             typename MatrixType::Scalar* /*tempData*/ = 0)
0287 {
0288   typedef typename MatrixType::Scalar Scalar;
0289   typedef Block<MatrixType,Dynamic,Dynamic> BlockType;
0290 
0291   Index rows = A.rows();
0292   Index cols = A.cols();
0293   Index size = (std::min)(rows, cols);
0294 
0295   // X and Y are work space
0296   enum { StorageOrder = traits<MatrixType>::Flags & RowMajorBit };
0297   Matrix<Scalar,
0298          MatrixType::RowsAtCompileTime,
0299          Dynamic,
0300          StorageOrder,
0301          MatrixType::MaxRowsAtCompileTime> X(rows,maxBlockSize);
0302   Matrix<Scalar,
0303          MatrixType::ColsAtCompileTime,
0304          Dynamic,
0305          StorageOrder,
0306          MatrixType::MaxColsAtCompileTime> Y(cols,maxBlockSize);
0307   Index blockSize = (std::min)(maxBlockSize,size);
0308 
0309   Index k = 0;
0310   for(k = 0; k < size; k += blockSize)
0311   {
0312     Index bs = (std::min)(size-k,blockSize);  // actual size of the block
0313     Index brows = rows - k;                   // rows of the block
0314     Index bcols = cols - k;                   // columns of the block
0315 
0316     // partition the matrix A:
0317     // 
0318     //      | A00 A01 A02 |
0319     //      |             |
0320     // A  = | A10 A11 A12 |
0321     //      |             |
0322     //      | A20 A21 A22 |
0323     //
0324     // where A11 is a bs x bs diagonal block,
0325     // and let:
0326     //      | A11 A12 |
0327     //  B = |         |
0328     //      | A21 A22 |
0329 
0330     BlockType B = A.block(k,k,brows,bcols);
0331     
0332     // This stage performs the bidiagonalization of A11, A21, A12, and updating of A22.
0333     // Finally, the algorithm continue on the updated A22.
0334     //
0335     // However, if B is too small, or A22 empty, then let's use an unblocked strategy
0336     if(k+bs==cols || bcols<48) // somewhat arbitrary threshold
0337     {
0338       upperbidiagonalization_inplace_unblocked(B,
0339                                                &(bidiagonal.template diagonal<0>().coeffRef(k)),
0340                                                &(bidiagonal.template diagonal<1>().coeffRef(k)),
0341                                                X.data()
0342                                               );
0343       break; // We're done
0344     }
0345     else
0346     {
0347       upperbidiagonalization_blocked_helper<BlockType>( B,
0348                                                         &(bidiagonal.template diagonal<0>().coeffRef(k)),
0349                                                         &(bidiagonal.template diagonal<1>().coeffRef(k)),
0350                                                         bs,
0351                                                         X.topLeftCorner(brows,bs),
0352                                                         Y.topLeftCorner(bcols,bs)
0353                                                       );
0354     }
0355   }
0356 }
0357 
0358 template<typename _MatrixType>
0359 UpperBidiagonalization<_MatrixType>& UpperBidiagonalization<_MatrixType>::computeUnblocked(const _MatrixType& matrix)
0360 {
0361   Index rows = matrix.rows();
0362   Index cols = matrix.cols();
0363   EIGEN_ONLY_USED_FOR_DEBUG(cols);
0364 
0365   eigen_assert(rows >= cols && "UpperBidiagonalization is only for Arices satisfying rows>=cols.");
0366 
0367   m_householder = matrix;
0368 
0369   ColVectorType temp(rows);
0370 
0371   upperbidiagonalization_inplace_unblocked(m_householder,
0372                                            &(m_bidiagonal.template diagonal<0>().coeffRef(0)),
0373                                            &(m_bidiagonal.template diagonal<1>().coeffRef(0)),
0374                                            temp.data());
0375 
0376   m_isInitialized = true;
0377   return *this;
0378 }
0379 
0380 template<typename _MatrixType>
0381 UpperBidiagonalization<_MatrixType>& UpperBidiagonalization<_MatrixType>::compute(const _MatrixType& matrix)
0382 {
0383   Index rows = matrix.rows();
0384   Index cols = matrix.cols();
0385   EIGEN_ONLY_USED_FOR_DEBUG(rows);
0386   EIGEN_ONLY_USED_FOR_DEBUG(cols);
0387 
0388   eigen_assert(rows >= cols && "UpperBidiagonalization is only for Arices satisfying rows>=cols.");
0389 
0390   m_householder = matrix;
0391   upperbidiagonalization_inplace_blocked(m_householder, m_bidiagonal);
0392             
0393   m_isInitialized = true;
0394   return *this;
0395 }
0396 
0397 #if 0
0398 /** \return the Householder QR decomposition of \c *this.
0399   *
0400   * \sa class Bidiagonalization
0401   */
0402 template<typename Derived>
0403 const UpperBidiagonalization<typename MatrixBase<Derived>::PlainObject>
0404 MatrixBase<Derived>::bidiagonalization() const
0405 {
0406   return UpperBidiagonalization<PlainObject>(eval());
0407 }
0408 #endif
0409 
0410 } // end namespace internal
0411 
0412 } // end namespace Eigen
0413 
0414 #endif // EIGEN_BIDIAGONALIZATION_H