2013-06-19 00:03:27 +02:00
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// We used the "A Divide-And-Conquer Algorithm for the Bidiagonal SVD"
// research report written by Ming Gu and Stanley C.Eisenstat
// The code variable names correspond to the names they used in their
// report
//
// 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>
2013-08-20 14:10:55 +01:00
// Copyright (C) 2013 Jitse Niesen <jitse@maths.leeds.ac.uk>
2017-11-08 10:24:28 +01:00
// Copyright (C) 2014-2017 Gael Guennebaud <gael.guennebaud@inria.fr>
2013-06-19 00:03:27 +02:00
//
// 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_BDCSVD_H
# define EIGEN_BDCSVD_H
2014-09-22 15:22:52 +02:00
// #define EIGEN_BDCSVD_DEBUG_VERBOSE
// #define EIGEN_BDCSVD_SANITY_CHECKS
2016-05-03 23:15:29 +02:00
2013-06-19 00:03:27 +02:00
namespace Eigen {
2014-09-01 18:16:20 +02:00
2014-10-15 11:59:21 +02:00
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
IOFormat bdcsvdfmt ( 8 , 0 , " , " , " \n " , " [ " , " ] " ) ;
# endif
2014-09-01 18:16:20 +02:00
template < typename _MatrixType > class BDCSVD ;
namespace internal {
template < typename _MatrixType >
struct traits < BDCSVD < _MatrixType > >
{
typedef _MatrixType MatrixType ;
} ;
} // end namespace internal
2013-06-19 00:03:27 +02:00
/** \ingroup SVD_Module
*
*
* \ class BDCSVD
*
* \ brief class Bidiagonal Divide and Conquer SVD
*
2016-01-01 21:45:06 +01:00
* \ tparam _MatrixType the type of the matrix of which we are computing the SVD decomposition
*
2016-05-04 12:53:14 +02:00
* This class first reduces the input matrix to bi - diagonal form using class UpperBidiagonalization ,
* and then performs a divide - and - conquer diagonalization . Small blocks are diagonalized using class JacobiSVD .
* You can control the switching size with the setSwitchSize ( ) method , default is 16.
* For small matrice ( < 16 ) , it is thus preferable to directly use JacobiSVD . For larger ones , BDCSVD is highly
* recommended and can several order of magnitude faster .
*
* \ warning this algorithm is unlikely to provide accurate result when compiled with unsafe math optimizations .
* For instance , this concerns Intel ' s compiler ( ICC ) , which perfroms such optimization by default unless
* you compile with the \ c - fp - model \ c precise option . Likewise , the \ c - ffast - math option of GCC or clang will
* significantly degrade the accuracy .
*
* \ sa class JacobiSVD
2013-06-19 00:03:27 +02:00
*/
template < typename _MatrixType >
2014-09-01 18:16:20 +02:00
class BDCSVD : public SVDBase < BDCSVD < _MatrixType > >
2013-06-19 00:03:27 +02:00
{
2014-09-01 18:16:20 +02:00
typedef SVDBase < BDCSVD > Base ;
2013-06-19 00:03:27 +02:00
public :
2013-07-17 09:20:30 +02:00
using Base : : rows ;
using Base : : cols ;
2014-09-02 22:30:23 +02:00
using Base : : computeU ;
using Base : : computeV ;
2013-07-17 09:20:30 +02:00
2013-06-19 00:03:27 +02:00
typedef _MatrixType MatrixType ;
2013-07-17 09:20:30 +02:00
typedef typename MatrixType : : Scalar Scalar ;
2013-06-19 00:03:27 +02:00
typedef typename NumTraits < typename MatrixType : : Scalar > : : Real RealScalar ;
2017-06-09 15:45:49 +02:00
typedef typename NumTraits < RealScalar > : : Literal Literal ;
2013-06-19 00:03:27 +02:00
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
} ;
2014-09-02 22:30:23 +02:00
typedef typename Base : : MatrixUType MatrixUType ;
typedef typename Base : : MatrixVType MatrixVType ;
typedef typename Base : : SingularValuesType SingularValuesType ;
2015-06-19 10:37:25 +02:00
typedef Matrix < Scalar , Dynamic , Dynamic , ColMajor > MatrixX ;
typedef Matrix < RealScalar , Dynamic , Dynamic , ColMajor > MatrixXr ;
2013-06-19 00:03:27 +02:00
typedef Matrix < RealScalar , Dynamic , 1 > VectorType ;
2013-08-27 15:30:11 +01:00
typedef Array < RealScalar , Dynamic , 1 > ArrayXr ;
2014-10-15 15:21:12 +02:00
typedef Array < Index , 1 , Dynamic > ArrayXi ;
2015-03-31 22:54:47 +02:00
typedef Ref < ArrayXr > ArrayRef ;
typedef Ref < ArrayXi > IndicesRef ;
2013-06-19 00:03:27 +02:00
/** \brief Default Constructor.
*
* The default constructor is useful in cases in which the user intends to
* perform decompositions via BDCSVD : : compute ( const MatrixType & ) .
*/
2014-09-03 10:15:24 +02:00
BDCSVD ( ) : m_algoswap ( 16 ) , m_numIters ( 0 )
2013-06-19 00:03:27 +02:00
{ }
/** \brief Default Constructor with memory preallocation
*
* Like the default constructor but with preallocation of the internal data
* according to the specified problem size .
* \ sa BDCSVD ( )
*/
BDCSVD ( Index rows , Index cols , unsigned int computationOptions = 0 )
2014-09-03 10:15:24 +02:00
: m_algoswap ( 16 ) , m_numIters ( 0 )
2013-06-19 00:03:27 +02:00
{
allocate ( rows , cols , computationOptions ) ;
}
/** \brief Constructor performing the decomposition of given matrix.
*
* \ param matrix the matrix to decompose
* \ param computationOptions optional parameter allowing to specify if you want full or thin U or V unitaries to be computed .
* By default , none is computed . This is a bit - field , the possible bits are # ComputeFullU , # ComputeThinU ,
* # ComputeFullV , # ComputeThinV .
*
* Thin unitaries are only available if your matrix type has a Dynamic number of columns ( for example MatrixXf ) . They also are not
* available with the ( non - default ) FullPivHouseholderQR preconditioner .
*/
BDCSVD ( const MatrixType & matrix , unsigned int computationOptions = 0 )
2014-09-03 10:15:24 +02:00
: m_algoswap ( 16 ) , m_numIters ( 0 )
2013-06-19 00:03:27 +02:00
{
compute ( matrix , computationOptions ) ;
}
~ BDCSVD ( )
{
}
2014-09-01 18:16:20 +02:00
2013-06-19 00:03:27 +02:00
/** \brief Method performing the decomposition of given matrix using custom options.
*
* \ param matrix the matrix to decompose
* \ param computationOptions optional parameter allowing to specify if you want full or thin U or V unitaries to be computed .
* By default , none is computed . This is a bit - field , the possible bits are # ComputeFullU , # ComputeThinU ,
* # ComputeFullV , # ComputeThinV .
*
* Thin unitaries are only available if your matrix type has a Dynamic number of columns ( for example MatrixXf ) . They also are not
* available with the ( non - default ) FullPivHouseholderQR preconditioner .
*/
2014-09-01 18:16:20 +02:00
BDCSVD & compute ( const MatrixType & matrix , unsigned int computationOptions ) ;
2013-06-19 00:03:27 +02:00
/** \brief Method performing the decomposition of given matrix using current options.
*
* \ param matrix the matrix to decompose
*
* This method uses the current \ a computationOptions , as already passed to the constructor or to compute ( const MatrixType & , unsigned int ) .
*/
2014-09-01 18:16:20 +02:00
BDCSVD & compute ( const MatrixType & matrix )
2013-06-19 00:03:27 +02:00
{
return compute ( matrix , this - > m_computationOptions ) ;
}
void setSwitchSize ( int s )
{
2013-08-07 16:34:34 +01:00
eigen_assert ( s > 3 & & " BDCSVD the size of the algo switch has to be greater than 3 " ) ;
2014-09-03 10:15:24 +02:00
m_algoswap = s ;
2013-06-19 00:03:27 +02:00
}
private :
void allocate ( Index rows , Index cols , unsigned int computationOptions ) ;
2013-08-27 15:30:11 +01:00
void divide ( Index firstCol , Index lastCol , Index firstRowW , Index firstColW , Index shift ) ;
2013-08-20 14:10:55 +01:00
void computeSVDofM ( Index firstCol , Index n , MatrixXr & U , VectorType & singVals , MatrixXr & V ) ;
2015-03-31 22:54:47 +02:00
void computeSingVals ( const ArrayRef & col0 , const ArrayRef & diag , const IndicesRef & perm , VectorType & singVals , ArrayRef shifts , ArrayRef mus ) ;
void perturbCol0 ( const ArrayRef & col0 , const ArrayRef & diag , const IndicesRef & perm , const VectorType & singVals , const ArrayRef & shifts , const ArrayRef & mus , ArrayRef zhat ) ;
void computeSingVecs ( const ArrayRef & zhat , const ArrayRef & diag , const IndicesRef & perm , const VectorType & singVals , const ArrayRef & shifts , const ArrayRef & mus , MatrixXr & U , MatrixXr & V ) ;
2013-06-19 00:03:27 +02:00
void deflation43 ( Index firstCol , Index shift , Index i , Index size ) ;
void deflation44 ( Index firstColu , Index firstColm , Index firstRowW , Index firstColW , Index i , Index j , Index size ) ;
void deflation ( Index firstCol , Index lastCol , Index k , Index firstRowW , Index firstColW , Index shift ) ;
2014-09-03 10:15:24 +02:00
template < typename HouseholderU , typename HouseholderV , typename NaiveU , typename NaiveV >
void copyUV ( const HouseholderU & householderU , const HouseholderV & householderV , const NaiveU & naiveU , const NaiveV & naivev ) ;
2015-03-31 22:54:47 +02:00
void structured_update ( Block < MatrixXr , Dynamic , Dynamic > A , const MatrixXr & B , Index n1 ) ;
static RealScalar secularEq ( RealScalar x , const ArrayRef & col0 , const ArrayRef & diag , const IndicesRef & perm , const ArrayRef & diagShifted , RealScalar shift ) ;
2013-06-19 00:03:27 +02:00
protected :
MatrixXr m_naiveU , m_naiveV ;
MatrixXr m_computed ;
2014-09-03 10:15:24 +02:00
Index m_nRec ;
2015-03-31 22:54:47 +02:00
ArrayXr m_workspace ;
ArrayXi m_workspaceI ;
2014-09-03 10:15:24 +02:00
int m_algoswap ;
bool m_isTranspose , m_compU , m_compV ;
using Base : : m_singularValues ;
using Base : : m_diagSize ;
using Base : : m_computeFullU ;
using Base : : m_computeFullV ;
using Base : : m_computeThinU ;
using Base : : m_computeThinV ;
using Base : : m_matrixU ;
using Base : : m_matrixV ;
using Base : : m_isInitialized ;
using Base : : m_nonzeroSingularValues ;
2013-08-27 15:30:11 +01:00
public :
int m_numIters ;
2013-06-19 00:03:27 +02:00
} ; //end class BDCSVD
2014-10-17 15:32:55 +02:00
// Method to allocate and initialize matrix and attributes
2013-06-19 00:03:27 +02:00
template < typename MatrixType >
void BDCSVD < MatrixType > : : allocate ( Index rows , Index cols , unsigned int computationOptions )
{
2014-09-03 10:15:24 +02:00
m_isTranspose = ( cols > rows ) ;
2014-09-22 15:22:52 +02:00
2014-09-03 10:15:24 +02:00
if ( Base : : allocate ( rows , cols , computationOptions ) )
return ;
2013-06-19 00:03:27 +02:00
2014-09-03 10:15:24 +02:00
m_computed = MatrixXr : : Zero ( m_diagSize + 1 , m_diagSize ) ;
m_compU = computeV ( ) ;
m_compV = computeU ( ) ;
if ( m_isTranspose )
std : : swap ( m_compU , m_compV ) ;
2013-06-19 00:03:27 +02:00
2014-09-03 10:15:24 +02:00
if ( m_compU ) m_naiveU = MatrixXr : : Zero ( m_diagSize + 1 , m_diagSize + 1 ) ;
else m_naiveU = MatrixXr : : Zero ( 2 , m_diagSize + 1 ) ;
if ( m_compV ) m_naiveV = MatrixXr : : Zero ( m_diagSize , m_diagSize ) ;
2015-03-31 22:54:47 +02:00
m_workspace . resize ( ( m_diagSize + 1 ) * ( m_diagSize + 1 ) * 3 ) ;
m_workspaceI . resize ( 3 * m_diagSize ) ;
2013-06-19 00:03:27 +02:00
} // end allocate
template < typename MatrixType >
2014-09-01 18:16:20 +02:00
BDCSVD < MatrixType > & BDCSVD < MatrixType > : : compute ( const MatrixType & matrix , unsigned int computationOptions )
2013-06-19 00:03:27 +02:00
{
2014-10-15 11:59:21 +02:00
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
std : : cout < < " \n \n \n ====================================================================================================================== \n \n \n " ;
# endif
2013-06-19 00:03:27 +02:00
allocate ( matrix . rows ( ) , matrix . cols ( ) , computationOptions ) ;
using std : : abs ;
2016-05-03 23:15:29 +02:00
const RealScalar considerZero = ( std : : numeric_limits < RealScalar > : : min ) ( ) ;
2013-06-19 00:03:27 +02:00
2015-03-24 13:38:07 +01:00
//**** step -1 - If the problem is too small, directly falls back to JacobiSVD and return
if ( matrix . cols ( ) < m_algoswap )
{
2015-03-31 22:54:47 +02:00
// FIXME this line involves temporaries
2015-03-24 13:38:07 +01:00
JacobiSVD < MatrixType > jsvd ( matrix , computationOptions ) ;
if ( computeU ( ) ) m_matrixU = jsvd . matrixU ( ) ;
if ( computeV ( ) ) m_matrixV = jsvd . matrixV ( ) ;
m_singularValues = jsvd . singularValues ( ) ;
m_nonzeroSingularValues = jsvd . nonzeroSingularValues ( ) ;
m_isInitialized = true ;
return * this ;
}
2014-10-06 19:35:57 +02:00
//**** step 0 - Copy the input matrix and apply scaling to reduce over/under-flows
RealScalar scale = matrix . cwiseAbs ( ) . maxCoeff ( ) ;
2017-06-09 15:45:49 +02:00
if ( scale = = Literal ( 0 ) ) scale = Literal ( 1 ) ;
2014-10-06 19:35:57 +02:00
MatrixX copy ;
if ( m_isTranspose ) copy = matrix . adjoint ( ) / scale ;
else copy = matrix / scale ;
//**** step 1 - Bidiagonalization
2015-03-31 22:54:47 +02:00
// FIXME this line involves temporaries
2013-08-21 14:34:48 +01:00
internal : : UpperBidiagonalization < MatrixX > bid ( copy ) ;
2013-06-19 00:03:27 +02:00
2014-10-06 19:35:57 +02:00
//**** step 2 - Divide & Conquer
2014-09-05 17:51:46 +02:00
m_naiveU . setZero ( ) ;
m_naiveV . setZero ( ) ;
2015-03-31 22:54:47 +02:00
// FIXME this line involves a temporary matrix
2014-09-03 10:15:24 +02:00
m_computed . topRows ( m_diagSize ) = bid . bidiagonal ( ) . toDenseMatrix ( ) . transpose ( ) ;
2013-08-07 16:34:34 +01:00
m_computed . template bottomRows < 1 > ( ) . setZero ( ) ;
2014-09-03 10:15:24 +02:00
divide ( 0 , m_diagSize - 1 , 0 , 0 , 0 ) ;
2013-06-19 00:03:27 +02:00
2014-10-06 19:35:57 +02:00
//**** step 3 - Copy singular values and vectors
2014-09-03 10:15:24 +02:00
for ( int i = 0 ; i < m_diagSize ; i + + )
{
2013-06-19 00:03:27 +02:00
RealScalar a = abs ( m_computed . coeff ( i , i ) ) ;
2014-10-06 19:35:57 +02:00
m_singularValues . coeffRef ( i ) = a * scale ;
2016-05-03 23:15:29 +02:00
if ( a < considerZero )
2014-09-03 10:15:24 +02:00
{
m_nonzeroSingularValues = i ;
m_singularValues . tail ( m_diagSize - i - 1 ) . setZero ( ) ;
2013-06-19 00:03:27 +02:00
break ;
}
2014-09-03 10:15:24 +02:00
else if ( i = = m_diagSize - 1 )
2013-06-19 00:03:27 +02:00
{
2014-09-03 10:15:24 +02:00
m_nonzeroSingularValues = i + 1 ;
2013-06-19 00:03:27 +02:00
break ;
}
}
2015-03-24 13:38:07 +01:00
2014-10-06 19:35:57 +02:00
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
2014-10-09 23:29:01 +02:00
// std::cout << "m_naiveU\n" << m_naiveU << "\n\n";
// std::cout << "m_naiveV\n" << m_naiveV << "\n\n";
2014-10-06 19:35:57 +02:00
# endif
2014-09-03 10:15:24 +02:00
if ( m_isTranspose ) copyUV ( bid . householderV ( ) , bid . householderU ( ) , m_naiveV , m_naiveU ) ;
else copyUV ( bid . householderU ( ) , bid . householderV ( ) , m_naiveU , m_naiveV ) ;
2014-10-06 19:35:57 +02:00
2014-09-03 10:15:24 +02:00
m_isInitialized = true ;
2013-06-19 00:03:27 +02:00
return * this ;
} // end compute
template < typename MatrixType >
2014-09-03 10:15:24 +02:00
template < typename HouseholderU , typename HouseholderV , typename NaiveU , typename NaiveV >
void BDCSVD < MatrixType > : : copyUV ( const HouseholderU & householderU , const HouseholderV & householderV , const NaiveU & naiveU , const NaiveV & naiveV )
2013-08-21 14:34:48 +01:00
{
2013-08-07 16:34:34 +01:00
// Note exchange of U and V: m_matrixU is set from m_naiveV and vice versa
2014-09-03 10:15:24 +02:00
if ( computeU ( ) )
{
2014-09-22 15:22:52 +02:00
Index Ucols = m_computeThinU ? m_diagSize : householderU . cols ( ) ;
2014-09-03 10:15:24 +02:00
m_matrixU = MatrixX : : Identity ( householderU . cols ( ) , Ucols ) ;
2014-09-22 15:22:52 +02:00
m_matrixU . topLeftCorner ( m_diagSize , m_diagSize ) = naiveV . template cast < Scalar > ( ) . topLeftCorner ( m_diagSize , m_diagSize ) ;
2015-03-31 22:54:47 +02:00
householderU . applyThisOnTheLeft ( m_matrixU ) ; // FIXME this line involves a temporary buffer
2013-06-19 00:03:27 +02:00
}
2014-09-03 10:15:24 +02:00
if ( computeV ( ) )
{
2014-09-22 15:22:52 +02:00
Index Vcols = m_computeThinV ? m_diagSize : householderV . cols ( ) ;
2014-09-03 10:15:24 +02:00
m_matrixV = MatrixX : : Identity ( householderV . cols ( ) , Vcols ) ;
2014-09-22 15:22:52 +02:00
m_matrixV . topLeftCorner ( m_diagSize , m_diagSize ) = naiveU . template cast < Scalar > ( ) . topLeftCorner ( m_diagSize , m_diagSize ) ;
2015-03-31 22:54:47 +02:00
householderV . applyThisOnTheLeft ( m_matrixV ) ; // FIXME this line involves a temporary buffer
2013-06-19 00:03:27 +02:00
}
}
2014-09-05 17:51:46 +02:00
/** \internal
* Performs A = A * B exploiting the special structure of the matrix A . Splitting A as :
* A = [ A1 ]
* [ A2 ]
* such that A1 . rows ( ) = = n1 , then we assume that at least half of the columns of A1 and A2 are zeros .
* We can thus pack them prior to the the matrix product . However , this is only worth the effort if the matrix is large
* enough .
*/
template < typename MatrixType >
void BDCSVD < MatrixType > : : structured_update ( Block < MatrixXr , Dynamic , Dynamic > A , const MatrixXr & B , Index n1 )
{
Index n = A . rows ( ) ;
if ( n > 100 )
{
2014-09-22 15:22:52 +02:00
// If the matrices are large enough, let's exploit the sparse structure of A by
2014-09-05 17:51:46 +02:00
// splitting it in half (wrt n1), and packing the non-zero columns.
2015-02-16 15:05:41 +01:00
Index n2 = n - n1 ;
2015-03-31 22:54:47 +02:00
Map < MatrixXr > A1 ( m_workspace . data ( ) , n1 , n ) ;
Map < MatrixXr > A2 ( m_workspace . data ( ) + n1 * n , n2 , n ) ;
Map < MatrixXr > B1 ( m_workspace . data ( ) + n * n , n , n ) ;
Map < MatrixXr > B2 ( m_workspace . data ( ) + 2 * n * n , n , n ) ;
2014-09-05 17:51:46 +02:00
Index k1 = 0 , k2 = 0 ;
for ( Index j = 0 ; j < n ; + + j )
{
2017-06-09 15:45:49 +02:00
if ( ( A . col ( j ) . head ( n1 ) . array ( ) ! = Literal ( 0 ) ) . any ( ) )
2014-09-05 17:51:46 +02:00
{
A1 . col ( k1 ) = A . col ( j ) . head ( n1 ) ;
B1 . row ( k1 ) = B . row ( j ) ;
+ + k1 ;
}
2017-06-09 15:45:49 +02:00
if ( ( A . col ( j ) . tail ( n2 ) . array ( ) ! = Literal ( 0 ) ) . any ( ) )
2014-09-05 17:51:46 +02:00
{
A2 . col ( k2 ) = A . col ( j ) . tail ( n2 ) ;
B2 . row ( k2 ) = B . row ( j ) ;
+ + k2 ;
}
}
A . topRows ( n1 ) . noalias ( ) = A1 . leftCols ( k1 ) * B1 . topRows ( k1 ) ;
A . bottomRows ( n2 ) . noalias ( ) = A2 . leftCols ( k2 ) * B2 . topRows ( k2 ) ;
}
else
2015-03-31 22:54:47 +02:00
{
Map < MatrixXr , Aligned > tmp ( m_workspace . data ( ) , n , n ) ;
tmp . noalias ( ) = A * B ;
A = tmp ;
}
2014-09-05 17:51:46 +02:00
}
2013-06-19 00:03:27 +02:00
// The divide algorithm is done "in place", we are always working on subsets of the same matrix. The divide methods takes as argument the
// place of the submatrix we are currently working on.
//@param firstCol : The Index of the first column of the submatrix of m_computed and for m_naiveU;
//@param lastCol : The Index of the last column of the submatrix of m_computed and for m_naiveU;
// lastCol + 1 - firstCol is the size of the submatrix.
//@param firstRowW : The Index of the first row of the matrix W that we are to change. (see the reference paper section 1 for more information on W)
//@param firstRowW : Same as firstRowW with the column.
//@param shift : Each time one takes the left submatrix, one must add 1 to the shift. Why? Because! We actually want the last column of the U submatrix
// to become the first column (*coeff) and to shift all the other columns to the right. There are more details on the reference paper.
template < typename MatrixType >
2014-09-03 10:15:24 +02:00
void BDCSVD < MatrixType > : : divide ( Index firstCol , Index lastCol , Index firstRowW , Index firstColW , Index shift )
2013-06-19 00:03:27 +02:00
{
2015-06-09 13:32:12 +02:00
// requires rows = cols + 1;
2013-06-19 00:03:27 +02:00
using std : : pow ;
using std : : sqrt ;
using std : : abs ;
const Index n = lastCol - firstCol + 1 ;
const Index k = n / 2 ;
2016-05-03 23:15:29 +02:00
const RealScalar considerZero = ( std : : numeric_limits < RealScalar > : : min ) ( ) ;
2013-06-19 00:03:27 +02:00
RealScalar alphaK ;
RealScalar betaK ;
RealScalar r0 ;
RealScalar lambda , phi , c0 , s0 ;
2014-09-04 09:17:01 +02:00
VectorType l , f ;
2013-06-19 00:03:27 +02:00
// We use the other algorithm which is more efficient for small
// matrices.
2014-09-03 10:15:24 +02:00
if ( n < m_algoswap )
{
2015-03-31 22:54:47 +02:00
// FIXME this line involves temporaries
JacobiSVD < MatrixXr > b ( m_computed . block ( firstCol , firstCol , n + 1 , n ) , ComputeFullU | ( m_compV ? ComputeFullV : 0 ) ) ;
2014-09-03 10:15:24 +02:00
if ( m_compU )
m_naiveU . block ( firstCol , firstCol , n + 1 , n + 1 ) . real ( ) = b . matrixU ( ) ;
2013-06-19 00:03:27 +02:00
else
{
2014-09-03 10:15:24 +02:00
m_naiveU . row ( 0 ) . segment ( firstCol , n + 1 ) . real ( ) = b . matrixU ( ) . row ( 0 ) ;
m_naiveU . row ( 1 ) . segment ( firstCol , n + 1 ) . real ( ) = b . matrixU ( ) . row ( n ) ;
2013-06-19 00:03:27 +02:00
}
2014-09-03 10:15:24 +02:00
if ( m_compV ) m_naiveV . block ( firstRowW , firstColW , n , n ) . real ( ) = b . matrixV ( ) ;
2013-06-19 00:03:27 +02:00
m_computed . block ( firstCol + shift , firstCol + shift , n + 1 , n ) . setZero ( ) ;
2014-09-03 10:15:24 +02:00
m_computed . diagonal ( ) . segment ( firstCol + shift , n ) = b . singularValues ( ) . head ( n ) ;
2013-06-19 00:03:27 +02:00
return ;
}
// We use the divide and conquer algorithm
alphaK = m_computed ( firstCol + k , firstCol + k ) ;
betaK = m_computed ( firstCol + k + 1 , firstCol + k ) ;
// The divide must be done in that order in order to have good results. Divide change the data inside the submatrices
// and the divide of the right submatrice reads one column of the left submatrice. That's why we need to treat the
// right submatrix before the left one.
divide ( k + 1 + firstCol , lastCol , k + 1 + firstRowW , k + 1 + firstColW , shift ) ;
divide ( firstCol , k - 1 + firstCol , firstRowW , firstColW + 1 , shift + 1 ) ;
2014-09-22 15:22:52 +02:00
2014-09-03 10:15:24 +02:00
if ( m_compU )
2013-06-19 00:03:27 +02:00
{
lambda = m_naiveU ( firstCol + k , firstCol + k ) ;
phi = m_naiveU ( firstCol + k + 1 , lastCol + 1 ) ;
}
else
{
lambda = m_naiveU ( 1 , firstCol + k ) ;
phi = m_naiveU ( 0 , lastCol + 1 ) ;
}
2014-09-03 10:15:24 +02:00
r0 = sqrt ( ( abs ( alphaK * lambda ) * abs ( alphaK * lambda ) ) + abs ( betaK * phi ) * abs ( betaK * phi ) ) ;
if ( m_compU )
2013-06-19 00:03:27 +02:00
{
l = m_naiveU . row ( firstCol + k ) . segment ( firstCol , k ) ;
f = m_naiveU . row ( firstCol + k + 1 ) . segment ( firstCol + k + 1 , n - k - 1 ) ;
}
else
{
l = m_naiveU . row ( 1 ) . segment ( firstCol , k ) ;
f = m_naiveU . row ( 0 ) . segment ( firstCol + k + 1 , n - k - 1 ) ;
}
2017-06-09 15:45:49 +02:00
if ( m_compV ) m_naiveV ( firstRowW + k , firstColW ) = Literal ( 1 ) ;
2016-05-03 23:15:29 +02:00
if ( r0 < considerZero )
2013-06-19 00:03:27 +02:00
{
2017-06-09 15:45:49 +02:00
c0 = Literal ( 1 ) ;
s0 = Literal ( 0 ) ;
2013-06-19 00:03:27 +02:00
}
else
{
c0 = alphaK * lambda / r0 ;
s0 = betaK * phi / r0 ;
}
2014-09-22 15:22:52 +02:00
# ifdef EIGEN_BDCSVD_SANITY_CHECKS
assert ( m_naiveU . allFinite ( ) ) ;
assert ( m_naiveV . allFinite ( ) ) ;
assert ( m_computed . allFinite ( ) ) ;
# endif
2014-09-03 10:15:24 +02:00
if ( m_compU )
2013-06-19 00:03:27 +02:00
{
MatrixXr q1 ( m_naiveU . col ( firstCol + k ) . segment ( firstCol , k + 1 ) ) ;
// we shiftW Q1 to the right
for ( Index i = firstCol + k - 1 ; i > = firstCol ; i - - )
2014-09-03 10:15:24 +02:00
m_naiveU . col ( i + 1 ) . segment ( firstCol , k + 1 ) = m_naiveU . col ( i ) . segment ( firstCol , k + 1 ) ;
2013-06-19 00:03:27 +02:00
// we shift q1 at the left with a factor c0
2014-09-03 10:15:24 +02:00
m_naiveU . col ( firstCol ) . segment ( firstCol , k + 1 ) = ( q1 * c0 ) ;
2013-06-19 00:03:27 +02:00
// last column = q1 * - s0
2014-09-03 10:15:24 +02:00
m_naiveU . col ( lastCol + 1 ) . segment ( firstCol , k + 1 ) = ( q1 * ( - s0 ) ) ;
2013-06-19 00:03:27 +02:00
// first column = q2 * s0
2014-09-03 10:15:24 +02:00
m_naiveU . col ( firstCol ) . segment ( firstCol + k + 1 , n - k ) = m_naiveU . col ( lastCol + 1 ) . segment ( firstCol + k + 1 , n - k ) * s0 ;
2013-06-19 00:03:27 +02:00
// q2 *= c0
2014-09-04 09:17:01 +02:00
m_naiveU . col ( lastCol + 1 ) . segment ( firstCol + k + 1 , n - k ) * = c0 ;
2013-06-19 00:03:27 +02:00
}
else
{
2015-03-24 13:38:07 +01:00
RealScalar q1 = m_naiveU ( 0 , firstCol + k ) ;
2013-06-19 00:03:27 +02:00
// we shift Q1 to the right
for ( Index i = firstCol + k - 1 ; i > = firstCol ; i - - )
m_naiveU ( 0 , i + 1 ) = m_naiveU ( 0 , i ) ;
// we shift q1 at the left with a factor c0
m_naiveU ( 0 , firstCol ) = ( q1 * c0 ) ;
// last column = q1 * - s0
m_naiveU ( 0 , lastCol + 1 ) = ( q1 * ( - s0 ) ) ;
// first column = q2 * s0
m_naiveU ( 1 , firstCol ) = m_naiveU ( 1 , lastCol + 1 ) * s0 ;
// q2 *= c0
m_naiveU ( 1 , lastCol + 1 ) * = c0 ;
m_naiveU . row ( 1 ) . segment ( firstCol + 1 , k ) . setZero ( ) ;
m_naiveU . row ( 0 ) . segment ( firstCol + k + 1 , n - k - 1 ) . setZero ( ) ;
}
2014-09-22 15:22:52 +02:00
# ifdef EIGEN_BDCSVD_SANITY_CHECKS
assert ( m_naiveU . allFinite ( ) ) ;
assert ( m_naiveV . allFinite ( ) ) ;
assert ( m_computed . allFinite ( ) ) ;
# endif
2013-06-19 00:03:27 +02:00
m_computed ( firstCol + shift , firstCol + shift ) = r0 ;
2014-09-03 10:15:24 +02:00
m_computed . col ( firstCol + shift ) . segment ( firstCol + shift + 1 , k ) = alphaK * l . transpose ( ) . real ( ) ;
m_computed . col ( firstCol + shift ) . segment ( firstCol + shift + k + 1 , n - k - 1 ) = betaK * f . transpose ( ) . real ( ) ;
2013-06-19 00:03:27 +02:00
2014-10-15 11:59:21 +02:00
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
ArrayXr tmp1 = ( m_computed . block ( firstCol + shift , firstCol + shift , n , n ) ) . jacobiSvd ( ) . singularValues ( ) ;
# endif
2013-08-20 14:10:55 +01:00
// Second part: try to deflate singular values in combined matrix
2013-06-19 00:03:27 +02:00
deflation ( firstCol , lastCol , k , firstRowW , firstColW , shift ) ;
2014-10-15 11:59:21 +02:00
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
ArrayXr tmp2 = ( m_computed . block ( firstCol + shift , firstCol + shift , n , n ) ) . jacobiSvd ( ) . singularValues ( ) ;
std : : cout < < " \n \n j1 = " < < tmp1 . transpose ( ) . format ( bdcsvdfmt ) < < " \n " ;
std : : cout < < " j2 = " < < tmp2 . transpose ( ) . format ( bdcsvdfmt ) < < " \n \n " ;
std : : cout < < " err: " < < ( ( tmp1 - tmp2 ) . abs ( ) > 1e-12 * tmp2 . abs ( ) ) . transpose ( ) < < " \n " ;
static int count = 0 ;
std : : cout < < " # " < < + + count < < " \n \n " ;
assert ( ( tmp1 - tmp2 ) . matrix ( ) . norm ( ) < 1e-14 * tmp2 . matrix ( ) . norm ( ) ) ;
// assert(count<681);
// assert(((tmp1-tmp2).abs()<1e-13*tmp2.abs()).all());
# endif
2013-08-20 14:10:55 +01:00
// Third part: compute SVD of combined matrix
MatrixXr UofSVD , VofSVD ;
VectorType singVals ;
computeSVDofM ( firstCol + shift , n , UofSVD , singVals , VofSVD ) ;
2014-09-05 17:51:46 +02:00
2014-09-22 15:22:52 +02:00
# ifdef EIGEN_BDCSVD_SANITY_CHECKS
assert ( UofSVD . allFinite ( ) ) ;
assert ( VofSVD . allFinite ( ) ) ;
# endif
2015-03-31 22:54:47 +02:00
if ( m_compU )
structured_update ( m_naiveU . block ( firstCol , firstCol , n + 1 , n + 1 ) , UofSVD , ( n + 2 ) / 2 ) ;
else
{
Map < Matrix < RealScalar , 2 , Dynamic > , Aligned > tmp ( m_workspace . data ( ) , 2 , n + 1 ) ;
tmp . noalias ( ) = m_naiveU . middleCols ( firstCol , n + 1 ) * UofSVD ;
m_naiveU . middleCols ( firstCol , n + 1 ) = tmp ;
}
2014-09-05 17:51:46 +02:00
if ( m_compV ) structured_update ( m_naiveV . block ( firstRowW , firstColW , n , n ) , VofSVD , ( n + 1 ) / 2 ) ;
2014-09-22 15:22:52 +02:00
# ifdef EIGEN_BDCSVD_SANITY_CHECKS
assert ( m_naiveU . allFinite ( ) ) ;
assert ( m_naiveV . allFinite ( ) ) ;
assert ( m_computed . allFinite ( ) ) ;
# endif
2013-08-20 14:10:55 +01:00
m_computed . block ( firstCol + shift , firstCol + shift , n , n ) . setZero ( ) ;
m_computed . block ( firstCol + shift , firstCol + shift , n , n ) . diagonal ( ) = singVals ;
} // end divide
2013-06-19 00:03:27 +02:00
2013-08-20 14:10:55 +01:00
// Compute SVD of m_computed.block(firstCol, firstCol, n + 1, n); this block only has non-zeros in
// the first column and on the diagonal and has undergone deflation, so diagonal is in increasing
// order except for possibly the (0,0) entry. The computed SVD is stored U, singVals and V, except
2014-09-03 10:15:24 +02:00
// that if m_compV is false, then V is not computed. Singular values are sorted in decreasing order.
2013-08-20 14:10:55 +01:00
//
// TODO Opportunities for optimization: better root finding algo, better stopping criterion, better
// handling of round-off errors, be consistent in ordering
2014-10-29 11:29:33 +01:00
// For instance, to solve the secular equation using FMM, see http://www.stat.uchicago.edu/~lekheng/courses/302/classics/greengard-rokhlin.pdf
2013-08-20 14:10:55 +01:00
template < typename MatrixType >
void BDCSVD < MatrixType > : : computeSVDofM ( Index firstCol , Index n , MatrixXr & U , VectorType & singVals , MatrixXr & V )
{
2016-05-03 23:15:29 +02:00
const RealScalar considerZero = ( std : : numeric_limits < RealScalar > : : min ) ( ) ;
using std : : abs ;
2015-03-31 22:54:47 +02:00
ArrayRef col0 = m_computed . col ( firstCol ) . segment ( firstCol , n ) ;
m_workspace . head ( n ) = m_computed . block ( firstCol , firstCol , n , n ) . diagonal ( ) ;
ArrayRef diag = m_workspace . head ( n ) ;
2017-06-09 15:45:49 +02:00
diag ( 0 ) = Literal ( 0 ) ;
2013-08-20 14:10:55 +01:00
2014-10-15 15:21:12 +02:00
// Allocate space for singular values and vectors
2013-08-20 14:10:55 +01:00
singVals . resize ( n ) ;
U . resize ( n + 1 , n + 1 ) ;
2014-09-03 10:15:24 +02:00
if ( m_compV ) V . resize ( n , n ) ;
2013-08-20 14:10:55 +01:00
2014-10-29 11:29:33 +01:00
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
if ( col0 . hasNaN ( ) | | diag . hasNaN ( ) )
std : : cout < < " \n \n HAS NAN \n \n " ;
# endif
2014-10-15 15:21:12 +02:00
// Many singular values might have been deflated, the zero ones have been moved to the end,
// but others are interleaved and we must ignore them at this stage.
// To this end, let's compute a permutation skipping them:
Index actual_n = n ;
2017-06-09 15:45:49 +02:00
while ( actual_n > 1 & & diag ( actual_n - 1 ) = = Literal ( 0 ) ) - - actual_n ;
2014-10-15 15:21:12 +02:00
Index m = 0 ; // size of the deflated problem
for ( Index k = 0 ; k < actual_n ; + + k )
2016-05-03 23:15:29 +02:00
if ( abs ( col0 ( k ) ) > considerZero )
2015-03-31 22:54:47 +02:00
m_workspaceI ( m + + ) = k ;
Map < ArrayXi > perm ( m_workspaceI . data ( ) , m ) ;
2014-09-22 15:22:52 +02:00
2015-03-31 22:54:47 +02:00
Map < ArrayXr > shifts ( m_workspace . data ( ) + 1 * n , n ) ;
Map < ArrayXr > mus ( m_workspace . data ( ) + 2 * n , n ) ;
Map < ArrayXr > zhat ( m_workspace . data ( ) + 3 * n , n ) ;
2014-09-22 15:22:52 +02:00
2014-10-29 11:29:33 +01:00
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
2014-09-22 15:22:52 +02:00
std : : cout < < " computeSVDofM using: \n " ;
std : : cout < < " z: " < < col0 . transpose ( ) < < " \n " ;
std : : cout < < " d: " < < diag . transpose ( ) < < " \n " ;
# endif
2014-09-04 09:17:01 +02:00
2014-09-22 15:22:52 +02:00
// Compute singVals, shifts, and mus
2014-10-15 15:21:12 +02:00
computeSingVals ( col0 , diag , perm , singVals , shifts , mus ) ;
2014-09-22 15:22:52 +02:00
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
2014-10-15 11:59:21 +02:00
std : : cout < < " j: " < < ( m_computed . block ( firstCol , firstCol , n , n ) ) . jacobiSvd ( ) . singularValues ( ) . transpose ( ) . reverse ( ) < < " \n \n " ;
2014-09-22 15:22:52 +02:00
std : : cout < < " sing-val: " < < singVals . transpose ( ) < < " \n " ;
std : : cout < < " mu: " < < mus . transpose ( ) < < " \n " ;
std : : cout < < " shift: " < < shifts . transpose ( ) < < " \n " ;
2014-10-15 11:59:21 +02:00
{
Index actual_n = n ;
2016-05-03 23:15:29 +02:00
while ( actual_n > 1 & & abs ( col0 ( actual_n - 1 ) ) < considerZero ) - - actual_n ;
2014-10-15 11:59:21 +02:00
std : : cout < < " \n \n mus: " < < mus . head ( actual_n ) . transpose ( ) < < " \n \n " ;
std : : cout < < " check1 (expect0) : " < < ( ( singVals . array ( ) - ( shifts + mus ) ) / singVals . array ( ) ) . head ( actual_n ) . transpose ( ) < < " \n \n " ;
std : : cout < < " check2 (>0) : " < < ( ( singVals . array ( ) - diag ) / singVals . array ( ) ) . head ( actual_n ) . transpose ( ) < < " \n \n " ;
std : : cout < < " check3 (>0) : " < < ( ( diag . segment ( 1 , actual_n - 1 ) - singVals . head ( actual_n - 1 ) . array ( ) ) / singVals . head ( actual_n - 1 ) . array ( ) ) . transpose ( ) < < " \n \n \n " ;
std : : cout < < " check4 (>0) : " < < ( ( singVals . segment ( 1 , actual_n - 1 ) - singVals . head ( actual_n - 1 ) ) ) . transpose ( ) < < " \n \n \n " ;
}
2014-09-22 15:22:52 +02:00
# endif
# ifdef EIGEN_BDCSVD_SANITY_CHECKS
assert ( singVals . allFinite ( ) ) ;
assert ( mus . allFinite ( ) ) ;
assert ( shifts . allFinite ( ) ) ;
# endif
// Compute zhat
2014-10-15 15:21:12 +02:00
perturbCol0 ( col0 , diag , perm , singVals , shifts , mus , zhat ) ;
2014-09-22 15:22:52 +02:00
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
std : : cout < < " zhat: " < < zhat . transpose ( ) < < " \n " ;
# endif
2014-10-15 11:59:21 +02:00
2014-09-22 15:22:52 +02:00
# ifdef EIGEN_BDCSVD_SANITY_CHECKS
assert ( zhat . allFinite ( ) ) ;
# endif
2014-10-15 15:21:12 +02:00
computeSingVecs ( zhat , diag , perm , singVals , shifts , mus , U , V ) ;
2014-09-22 15:22:52 +02:00
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
2014-10-06 19:35:57 +02:00
std : : cout < < " U^T U: " < < ( U . transpose ( ) * U - MatrixXr ( MatrixXr : : Identity ( U . cols ( ) , U . cols ( ) ) ) ) . norm ( ) < < " \n " ;
std : : cout < < " V^T V: " < < ( V . transpose ( ) * V - MatrixXr ( MatrixXr : : Identity ( V . cols ( ) , V . cols ( ) ) ) ) . norm ( ) < < " \n " ;
2014-09-22 15:22:52 +02:00
# endif
# ifdef EIGEN_BDCSVD_SANITY_CHECKS
2014-10-17 15:32:55 +02:00
assert ( U . allFinite ( ) ) ;
assert ( V . allFinite ( ) ) ;
2014-10-06 19:35:57 +02:00
assert ( ( U . transpose ( ) * U - MatrixXr ( MatrixXr : : Identity ( U . cols ( ) , U . cols ( ) ) ) ) . norm ( ) < 1e-14 * n ) ;
assert ( ( V . transpose ( ) * V - MatrixXr ( MatrixXr : : Identity ( V . cols ( ) , V . cols ( ) ) ) ) . norm ( ) < 1e-14 * n ) ;
2014-09-22 15:22:52 +02:00
assert ( m_naiveU . allFinite ( ) ) ;
assert ( m_naiveV . allFinite ( ) ) ;
assert ( m_computed . allFinite ( ) ) ;
# endif
2014-10-15 11:59:21 +02:00
// Because of deflation, the singular values might not be completely sorted.
// Fortunately, reordering them is a O(n) problem
for ( Index i = 0 ; i < actual_n - 1 ; + + i )
{
if ( singVals ( i ) > singVals ( i + 1 ) )
{
using std : : swap ;
swap ( singVals ( i ) , singVals ( i + 1 ) ) ;
U . col ( i ) . swap ( U . col ( i + 1 ) ) ;
if ( m_compV ) V . col ( i ) . swap ( V . col ( i + 1 ) ) ;
}
}
// Reverse order so that singular values in increased order
// Because of deflation, the zeros singular-values are already at the end
2014-09-22 15:22:52 +02:00
singVals . head ( actual_n ) . reverseInPlace ( ) ;
2015-03-31 22:54:47 +02:00
U . leftCols ( actual_n ) . rowwise ( ) . reverseInPlace ( ) ;
if ( m_compV ) V . leftCols ( actual_n ) . rowwise ( ) . reverseInPlace ( ) ;
2014-10-15 11:59:21 +02:00
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
JacobiSVD < MatrixXr > jsvd ( m_computed . block ( firstCol , firstCol , n , n ) ) ;
std : : cout < < " * j: " < < jsvd . singularValues ( ) . transpose ( ) < < " \n \n " ;
std : : cout < < " * sing-val: " < < singVals . transpose ( ) < < " \n " ;
// std::cout << " * err: " << ((jsvd.singularValues()-singVals)>1e-13*singVals.norm()).transpose() << "\n";
# endif
2014-09-22 15:22:52 +02:00
}
template < typename MatrixType >
2015-03-31 22:54:47 +02:00
typename BDCSVD < MatrixType > : : RealScalar BDCSVD < MatrixType > : : secularEq ( RealScalar mu , const ArrayRef & col0 , const ArrayRef & diag , const IndicesRef & perm , const ArrayRef & diagShifted , RealScalar shift )
2014-09-22 15:22:52 +02:00
{
2014-10-15 15:21:12 +02:00
Index m = perm . size ( ) ;
2017-06-09 15:45:49 +02:00
RealScalar res = Literal ( 1 ) ;
2014-10-15 15:21:12 +02:00
for ( Index i = 0 ; i < m ; + + i )
{
Index j = perm ( i ) ;
2017-11-08 10:24:28 +01:00
// The following expression could be rewritten to involve only a single division,
// but this would make the expression more sensitive to overflow.
res + = ( col0 ( j ) / ( diagShifted ( j ) - mu ) ) * ( col0 ( j ) / ( diag ( j ) + shift + mu ) ) ;
2014-10-15 15:21:12 +02:00
}
return res ;
2016-05-03 23:15:29 +02:00
2013-08-27 15:30:11 +01:00
}
template < typename MatrixType >
2015-03-31 22:54:47 +02:00
void BDCSVD < MatrixType > : : computeSingVals ( const ArrayRef & col0 , const ArrayRef & diag , const IndicesRef & perm ,
VectorType & singVals , ArrayRef shifts , ArrayRef mus )
2013-08-27 15:30:11 +01:00
{
using std : : abs ;
using std : : swap ;
2017-11-08 10:24:28 +01:00
using std : : sqrt ;
2013-08-27 15:30:11 +01:00
Index n = col0 . size ( ) ;
2014-09-22 15:22:52 +02:00
Index actual_n = n ;
2017-11-08 10:24:28 +01:00
// Note that here actual_n is computed based on col0(i)==0 instead of diag(i)==0 as above
// because 1) we have diag(i)==0 => col0(i)==0 and 2) if col0(i)==0, then diag(i) is already a singular value.
2017-06-09 15:45:49 +02:00
while ( actual_n > 1 & & col0 ( actual_n - 1 ) = = Literal ( 0 ) ) - - actual_n ;
2014-10-15 11:59:21 +02:00
2014-09-03 10:15:24 +02:00
for ( Index k = 0 ; k < n ; + + k )
{
2017-06-09 15:45:49 +02:00
if ( col0 ( k ) = = Literal ( 0 ) | | actual_n = = 1 )
2014-09-03 10:15:24 +02:00
{
2014-10-09 23:29:01 +02:00
// if col0(k) == 0, then entry is deflated, so singular value is on diagonal
// if actual_n==1, then the deflated problem is already diagonalized
2014-10-15 11:59:21 +02:00
singVals ( k ) = k = = 0 ? col0 ( 0 ) : diag ( k ) ;
2017-06-09 15:45:49 +02:00
mus ( k ) = Literal ( 0 ) ;
2014-10-15 11:59:21 +02:00
shifts ( k ) = k = = 0 ? col0 ( 0 ) : diag ( k ) ;
2013-08-20 14:10:55 +01:00
continue ;
}
2013-06-19 00:03:27 +02:00
2013-08-27 15:30:11 +01:00
// otherwise, use secular equation to find singular value
2013-08-20 14:10:55 +01:00
RealScalar left = diag ( k ) ;
2014-10-09 23:29:01 +02:00
RealScalar right ; // was: = (k != actual_n-1) ? diag(k+1) : (diag(actual_n-1) + col0.matrix().norm());
if ( k = = actual_n - 1 )
right = ( diag ( actual_n - 1 ) + col0 . matrix ( ) . norm ( ) ) ;
else
{
2017-11-08 10:24:28 +01:00
// Skip deflated singular values,
// recall that at this stage we assume that z[j]!=0 and all entries for which z[j]==0 have been put aside.
// This should be equivalent to using perm[]
2014-10-09 23:29:01 +02:00
Index l = k + 1 ;
2017-06-09 15:45:49 +02:00
while ( col0 ( l ) = = Literal ( 0 ) ) { + + l ; eigen_internal_assert ( l < actual_n ) ; }
2014-10-09 23:29:01 +02:00
right = diag ( l ) ;
}
2013-08-20 14:10:55 +01:00
// first decide whether it's closer to the left end or the right end
2017-06-09 15:45:49 +02:00
RealScalar mid = left + ( right - left ) / Literal ( 2 ) ;
RealScalar fMid = secularEq ( mid , col0 , diag , perm , diag , Literal ( 0 ) ) ;
2014-10-15 11:59:21 +02:00
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
std : : cout < < right - left < < " \n " ;
2014-10-15 15:21:12 +02:00
std : : cout < < " fMid = " < < fMid < < " " < < secularEq ( mid - left , col0 , diag , perm , diag - left , left ) < < " " < < secularEq ( mid - right , col0 , diag , perm , diag - right , right ) < < " \n " ;
std : : cout < < " = " < < secularEq ( 0.1 * ( left + right ) , col0 , diag , perm , diag , 0 )
< < " " < < secularEq ( 0.2 * ( left + right ) , col0 , diag , perm , diag , 0 )
< < " " < < secularEq ( 0.3 * ( left + right ) , col0 , diag , perm , diag , 0 )
< < " " < < secularEq ( 0.4 * ( left + right ) , col0 , diag , perm , diag , 0 )
< < " " < < secularEq ( 0.49 * ( left + right ) , col0 , diag , perm , diag , 0 )
< < " " < < secularEq ( 0.5 * ( left + right ) , col0 , diag , perm , diag , 0 )
< < " " < < secularEq ( 0.51 * ( left + right ) , col0 , diag , perm , diag , 0 )
< < " " < < secularEq ( 0.6 * ( left + right ) , col0 , diag , perm , diag , 0 )
< < " " < < secularEq ( 0.7 * ( left + right ) , col0 , diag , perm , diag , 0 )
< < " " < < secularEq ( 0.8 * ( left + right ) , col0 , diag , perm , diag , 0 )
< < " " < < secularEq ( 0.9 * ( left + right ) , col0 , diag , perm , diag , 0 ) < < " \n " ;
2014-10-15 11:59:21 +02:00
# endif
2017-06-09 15:45:49 +02:00
RealScalar shift = ( k = = actual_n - 1 | | fMid > Literal ( 0 ) ) ? left : right ;
2013-08-27 15:30:11 +01:00
// measure everything relative to shift
2015-03-31 22:54:47 +02:00
Map < ArrayXr > diagShifted ( m_workspace . data ( ) + 4 * n , n ) ;
diagShifted = diag - shift ;
2013-08-27 15:30:11 +01:00
// initial guess
RealScalar muPrev , muCur ;
2014-09-03 10:15:24 +02:00
if ( shift = = left )
{
2016-05-05 13:35:45 +02:00
muPrev = ( right - left ) * RealScalar ( 0.1 ) ;
2014-09-22 15:22:52 +02:00
if ( k = = actual_n - 1 ) muCur = right - left ;
2016-05-05 13:35:45 +02:00
else muCur = ( right - left ) * RealScalar ( 0.5 ) ;
2014-09-03 10:15:24 +02:00
}
else
{
2016-05-05 13:35:45 +02:00
muPrev = - ( right - left ) * RealScalar ( 0.1 ) ;
muCur = - ( right - left ) * RealScalar ( 0.5 ) ;
2013-08-27 15:30:11 +01:00
}
2014-10-15 15:21:12 +02:00
RealScalar fPrev = secularEq ( muPrev , col0 , diag , perm , diagShifted , shift ) ;
RealScalar fCur = secularEq ( muCur , col0 , diag , perm , diagShifted , shift ) ;
2014-09-03 10:15:24 +02:00
if ( abs ( fPrev ) < abs ( fCur ) )
{
2013-08-27 15:30:11 +01:00
swap ( fPrev , fCur ) ;
swap ( muPrev , muCur ) ;
2013-08-20 14:10:55 +01:00
}
2013-08-27 15:30:11 +01:00
// rational interpolation: fit a function of the form a / mu + b through the two previous
// iterates and use its zero to compute the next iterate
2017-06-09 15:45:49 +02:00
bool useBisection = fPrev * fCur > Literal ( 0 ) ;
while ( fCur ! = Literal ( 0 ) & & abs ( muCur - muPrev ) > Literal ( 8 ) * NumTraits < RealScalar > : : epsilon ( ) * numext : : maxi < RealScalar > ( abs ( muCur ) , abs ( muPrev ) ) & & abs ( fCur - fPrev ) > NumTraits < RealScalar > : : epsilon ( ) & & ! useBisection )
2014-09-03 10:15:24 +02:00
{
2013-08-27 15:30:11 +01:00
+ + m_numIters ;
2014-10-15 11:59:21 +02:00
// Find a and b such that the function f(mu) = a / mu + b matches the current and previous samples.
2017-06-09 15:45:49 +02:00
RealScalar a = ( fCur - fPrev ) / ( Literal ( 1 ) / muCur - Literal ( 1 ) / muPrev ) ;
2013-08-27 15:30:11 +01:00
RealScalar b = fCur - a / muCur ;
2014-10-15 11:59:21 +02:00
// And find mu such that f(mu)==0:
RealScalar muZero = - a / b ;
2014-10-15 15:21:12 +02:00
RealScalar fZero = secularEq ( muZero , col0 , diag , perm , diagShifted , shift ) ;
2014-10-15 11:59:21 +02:00
2013-08-27 15:30:11 +01:00
muPrev = muCur ;
fPrev = fCur ;
2014-10-15 11:59:21 +02:00
muCur = muZero ;
fCur = fZero ;
2013-08-27 15:30:11 +01:00
2017-06-09 15:45:49 +02:00
if ( shift = = left & & ( muCur < Literal ( 0 ) | | muCur > right - left ) ) useBisection = true ;
if ( shift = = right & & ( muCur < - ( right - left ) | | muCur > Literal ( 0 ) ) ) useBisection = true ;
2014-10-15 11:59:21 +02:00
if ( abs ( fCur ) > abs ( fPrev ) ) useBisection = true ;
2013-08-27 15:30:11 +01:00
}
// fall back on bisection method if rational interpolation did not work
2014-09-03 10:15:24 +02:00
if ( useBisection )
{
2014-10-09 23:29:01 +02:00
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
std : : cout < < " useBisection for k = " < < k < < " , actual_n = " < < actual_n < < " \n " ;
# endif
2013-08-27 15:30:11 +01:00
RealScalar leftShifted , rightShifted ;
2014-09-03 10:15:24 +02:00
if ( shift = = left )
{
2017-11-08 10:24:28 +01:00
// to avoid overflow, we must have mu > max(real_min, |z(k)|/sqrt(real_max)),
// the factor 2 is to be more conservative
2018-04-13 20:22:57 +02:00
leftShifted = numext : : maxi < RealScalar > ( ( std : : numeric_limits < RealScalar > : : min ) ( ) , Literal ( 2 ) * abs ( col0 ( k ) ) / sqrt ( ( std : : numeric_limits < RealScalar > : : max ) ( ) ) ) ;
2017-11-08 10:24:28 +01:00
// check that we did it right:
2017-12-15 17:53:48 +01:00
eigen_internal_assert ( ( numext : : isfinite ) ( ( col0 ( k ) / leftShifted ) * ( col0 ( k ) / ( diag ( k ) + shift + leftShifted ) ) ) ) ;
2014-10-09 23:29:01 +02:00
// I don't understand why the case k==0 would be special there:
2017-11-08 10:24:28 +01:00
// if (k == 0) rightShifted = right - left; else
rightShifted = ( k = = actual_n - 1 ) ? right : ( ( right - left ) * RealScalar ( 0.51 ) ) ; // theoretically we can take 0.5, but let's be safe
2014-09-03 10:15:24 +02:00
}
else
{
2017-11-08 10:24:28 +01:00
leftShifted = - ( right - left ) * RealScalar ( 0.51 ) ;
if ( k + 1 < n )
2018-04-13 20:22:57 +02:00
rightShifted = - numext : : maxi < RealScalar > ( ( std : : numeric_limits < RealScalar > : : min ) ( ) , abs ( col0 ( k + 1 ) ) / sqrt ( ( std : : numeric_limits < RealScalar > : : max ) ( ) ) ) ;
2017-11-08 10:24:28 +01:00
else
rightShifted = - ( std : : numeric_limits < RealScalar > : : min ) ( ) ;
2013-08-27 15:30:11 +01:00
}
2014-10-15 15:21:12 +02:00
RealScalar fLeft = secularEq ( leftShifted , col0 , diag , perm , diagShifted , shift ) ;
2014-09-22 15:22:52 +02:00
2015-03-31 09:23:53 +02:00
# if defined EIGEN_INTERNAL_DEBUGGING || defined EIGEN_BDCSVD_DEBUG_VERBOSE
2015-03-31 00:49:08 +02:00
RealScalar fRight = secularEq ( rightShifted , col0 , diag , perm , diagShifted , shift ) ;
2015-03-31 09:23:53 +02:00
# endif
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
2014-10-15 11:59:21 +02:00
if ( ! ( fLeft * fRight < 0 ) )
2016-05-03 23:15:29 +02:00
{
std : : cout < < " fLeft: " < < leftShifted < < " - " < < diagShifted . head ( 10 ) . transpose ( ) < < " \n ; " < < bool ( left = = shift ) < < " " < < ( left - shift ) < < " \n " ;
2014-10-09 23:29:01 +02:00
std : : cout < < k < < " : " < < fLeft < < " * " < < fRight < < " == " < < fLeft * fRight < < " ; " < < left < < " - " < < right < < " -> " < < leftShifted < < " " < < rightShifted < < " shift= " < < shift < < " \n " ;
2016-05-03 23:15:29 +02:00
}
2014-09-22 15:22:52 +02:00
# endif
2017-06-09 15:45:49 +02:00
eigen_internal_assert ( fLeft * fRight < Literal ( 0 ) ) ;
2013-08-27 15:30:11 +01:00
2017-06-09 15:45:49 +02:00
while ( rightShifted - leftShifted > Literal ( 2 ) * NumTraits < RealScalar > : : epsilon ( ) * numext : : maxi < RealScalar > ( abs ( leftShifted ) , abs ( rightShifted ) ) )
2014-09-03 10:15:24 +02:00
{
2017-06-09 15:45:49 +02:00
RealScalar midShifted = ( leftShifted + rightShifted ) / Literal ( 2 ) ;
2015-06-09 09:11:12 +02:00
fMid = secularEq ( midShifted , col0 , diag , perm , diagShifted , shift ) ;
2017-06-09 15:45:49 +02:00
if ( fLeft * fMid < Literal ( 0 ) )
2014-09-03 10:15:24 +02:00
{
2013-08-27 15:30:11 +01:00
rightShifted = midShifted ;
2014-09-03 10:15:24 +02:00
}
else
{
2013-08-27 15:30:11 +01:00
leftShifted = midShifted ;
fLeft = fMid ;
}
2013-08-20 14:10:55 +01:00
}
2013-08-27 15:30:11 +01:00
2017-06-09 15:45:49 +02:00
muCur = ( leftShifted + rightShifted ) / Literal ( 2 ) ;
2013-08-20 14:10:55 +01:00
}
2013-08-27 15:30:11 +01:00
singVals [ k ] = shift + muCur ;
2013-08-20 14:10:55 +01:00
shifts [ k ] = shift ;
2013-08-27 15:30:11 +01:00
mus [ k ] = muCur ;
2013-08-20 14:10:55 +01:00
// perturb singular value slightly if it equals diagonal entry to avoid division by zero later
// (deflation is supposed to avoid this from happening)
2014-10-09 23:29:01 +02:00
// - this does no seem to be necessary anymore -
// if (singVals[k] == left) singVals[k] *= 1 + NumTraits<RealScalar>::epsilon();
// if (singVals[k] == right) singVals[k] *= 1 - NumTraits<RealScalar>::epsilon();
2013-08-20 14:10:55 +01:00
}
2013-08-27 15:30:11 +01:00
}
2013-08-20 14:10:55 +01:00
2013-08-27 15:30:11 +01:00
// zhat is perturbation of col0 for which singular vectors can be computed stably (see Section 3.1)
template < typename MatrixType >
void BDCSVD < MatrixType > : : perturbCol0
2015-03-31 22:54:47 +02:00
( const ArrayRef & col0 , const ArrayRef & diag , const IndicesRef & perm , const VectorType & singVals ,
const ArrayRef & shifts , const ArrayRef & mus , ArrayRef zhat )
2013-08-27 15:30:11 +01:00
{
2014-09-03 10:15:24 +02:00
using std : : sqrt ;
2013-08-27 15:30:11 +01:00
Index n = col0 . size ( ) ;
2014-10-15 15:21:12 +02:00
Index m = perm . size ( ) ;
2014-10-17 15:32:55 +02:00
if ( m = = 0 )
{
zhat . setZero ( ) ;
return ;
}
2014-10-24 13:19:19 +02:00
Index last = perm ( m - 1 ) ;
2014-09-22 15:22:52 +02:00
// The offset permits to skip deflated entries while computing zhat
2014-09-03 10:15:24 +02:00
for ( Index k = 0 ; k < n ; + + k )
{
2017-06-09 15:45:49 +02:00
if ( col0 ( k ) = = Literal ( 0 ) ) // deflated
zhat ( k ) = Literal ( 0 ) ;
2014-09-03 10:15:24 +02:00
else
{
2013-08-20 14:10:55 +01:00
// see equation (3.6)
2014-09-22 15:22:52 +02:00
RealScalar dk = diag ( k ) ;
2014-10-15 15:21:12 +02:00
RealScalar prod = ( singVals ( last ) + dk ) * ( mus ( last ) + ( shifts ( last ) - dk ) ) ;
2014-09-22 15:22:52 +02:00
for ( Index l = 0 ; l < m ; + + l )
{
Index i = perm ( l ) ;
if ( i ! = k )
{
Index j = i < k ? i : perm ( l - 1 ) ;
prod * = ( ( singVals ( j ) + dk ) / ( ( diag ( i ) + dk ) ) ) * ( ( mus ( j ) + ( shifts ( j ) - dk ) ) / ( ( diag ( i ) - dk ) ) ) ;
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
if ( i ! = k & & std : : abs ( ( ( singVals ( j ) + dk ) * ( mus ( j ) + ( shifts ( j ) - dk ) ) ) / ( ( diag ( i ) + dk ) * ( diag ( i ) - dk ) ) - 1 ) > 0.9 )
2014-10-15 11:59:21 +02:00
std : : cout < < " " < < ( ( singVals ( j ) + dk ) * ( mus ( j ) + ( shifts ( j ) - dk ) ) ) / ( ( diag ( i ) + dk ) * ( diag ( i ) - dk ) ) < < " == ( " < < ( singVals ( j ) + dk ) < < " * " < < ( mus ( j ) + ( shifts ( j ) - dk ) )
< < " ) / ( " < < ( diag ( i ) + dk ) < < " * " < < ( diag ( i ) - dk ) < < " ) \n " ;
2014-09-22 15:22:52 +02:00
# endif
}
}
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
2014-10-15 15:21:12 +02:00
std : : cout < < " zhat( " < < k < < " ) = sqrt( " < < prod < < " ) ; " < < ( singVals ( last ) + dk ) < < " * " < < mus ( last ) + shifts ( last ) < < " - " < < dk < < " \n " ;
2014-09-22 15:22:52 +02:00
# endif
RealScalar tmp = sqrt ( prod ) ;
2017-06-09 15:45:49 +02:00
zhat ( k ) = col0 ( k ) > Literal ( 0 ) ? tmp : - tmp ;
2013-08-20 14:10:55 +01:00
}
}
2013-08-27 15:30:11 +01:00
}
2013-08-20 14:10:55 +01:00
2013-08-27 15:30:11 +01:00
// compute singular vectors
template < typename MatrixType >
void BDCSVD < MatrixType > : : computeSingVecs
2015-03-31 22:54:47 +02:00
( const ArrayRef & zhat , const ArrayRef & diag , const IndicesRef & perm , const VectorType & singVals ,
const ArrayRef & shifts , const ArrayRef & mus , MatrixXr & U , MatrixXr & V )
2013-08-27 15:30:11 +01:00
{
Index n = zhat . size ( ) ;
2014-10-15 15:21:12 +02:00
Index m = perm . size ( ) ;
2014-09-22 15:22:52 +02:00
2014-09-03 10:15:24 +02:00
for ( Index k = 0 ; k < n ; + + k )
{
2017-06-09 15:45:49 +02:00
if ( zhat ( k ) = = Literal ( 0 ) )
2014-09-03 10:15:24 +02:00
{
2013-08-20 14:10:55 +01:00
U . col ( k ) = VectorType : : Unit ( n + 1 , k ) ;
2014-09-03 10:15:24 +02:00
if ( m_compV ) V . col ( k ) = VectorType : : Unit ( n , k ) ;
}
else
{
2014-09-22 15:22:52 +02:00
U . col ( k ) . setZero ( ) ;
for ( Index l = 0 ; l < m ; + + l )
{
Index i = perm ( l ) ;
U ( i , k ) = zhat ( i ) / ( ( ( diag ( i ) - shifts ( k ) ) - mus ( k ) ) ) / ( ( diag ( i ) + singVals [ k ] ) ) ;
}
2017-06-09 15:45:49 +02:00
U ( n , k ) = Literal ( 0 ) ;
2013-08-20 14:10:55 +01:00
U . col ( k ) . normalize ( ) ;
2014-09-03 10:15:24 +02:00
if ( m_compV )
{
2014-09-22 15:22:52 +02:00
V . col ( k ) . setZero ( ) ;
for ( Index l = 1 ; l < m ; + + l )
{
Index i = perm ( l ) ;
V ( i , k ) = diag ( i ) * zhat ( i ) / ( ( ( diag ( i ) - shifts ( k ) ) - mus ( k ) ) ) / ( ( diag ( i ) + singVals [ k ] ) ) ;
}
2017-06-09 15:45:49 +02:00
V ( 0 , k ) = Literal ( - 1 ) ;
2013-08-20 14:10:55 +01:00
V . col ( k ) . normalize ( ) ;
}
}
}
U . col ( n ) = VectorType : : Unit ( n + 1 , n ) ;
}
2013-06-19 00:03:27 +02:00
// page 12_13
// i >= 1, di almost null and zi non null.
// We use a rotation to zero out zi applied to the left of M
template < typename MatrixType >
2014-09-03 10:15:24 +02:00
void BDCSVD < MatrixType > : : deflation43 ( Index firstCol , Index shift , Index i , Index size )
{
2013-06-19 00:03:27 +02:00
using std : : abs ;
using std : : sqrt ;
using std : : pow ;
2014-09-22 15:22:52 +02:00
Index start = firstCol + shift ;
RealScalar c = m_computed ( start , start ) ;
RealScalar s = m_computed ( start + i , start ) ;
2017-11-08 10:24:28 +01:00
RealScalar r = numext : : hypot ( c , s ) ;
2017-06-09 15:45:49 +02:00
if ( r = = Literal ( 0 ) )
2014-09-03 10:15:24 +02:00
{
2017-06-09 15:45:49 +02:00
m_computed ( start + i , start + i ) = Literal ( 0 ) ;
2013-06-19 00:03:27 +02:00
return ;
}
2014-09-22 15:22:52 +02:00
m_computed ( start , start ) = r ;
2017-06-09 15:45:49 +02:00
m_computed ( start + i , start ) = Literal ( 0 ) ;
m_computed ( start + i , start + i ) = Literal ( 0 ) ;
2014-09-22 15:22:52 +02:00
JacobiRotation < RealScalar > J ( c / r , - s / r ) ;
if ( m_compU ) m_naiveU . middleRows ( firstCol , size + 1 ) . applyOnTheRight ( firstCol , firstCol + i , J ) ;
else m_naiveU . applyOnTheRight ( firstCol , firstCol + i , J ) ;
2013-06-19 00:03:27 +02:00
} // end deflation 43
// page 13
2014-10-15 11:59:21 +02:00
// i,j >= 1, i!=j and |di - dj| < epsilon * norm2(M)
2013-06-19 00:03:27 +02:00
// We apply two rotations to have zj = 0;
2014-09-22 15:22:52 +02:00
// TODO deflation44 is still broken and not properly tested
2013-06-19 00:03:27 +02:00
template < typename MatrixType >
2014-09-03 10:15:24 +02:00
void BDCSVD < MatrixType > : : deflation44 ( Index firstColu , Index firstColm , Index firstRowW , Index firstColW , Index i , Index j , Index size )
{
2013-06-19 00:03:27 +02:00
using std : : abs ;
using std : : sqrt ;
using std : : conj ;
using std : : pow ;
2014-09-22 15:22:52 +02:00
RealScalar c = m_computed ( firstColm + i , firstColm ) ;
RealScalar s = m_computed ( firstColm + j , firstColm ) ;
RealScalar r = sqrt ( numext : : abs2 ( c ) + numext : : abs2 ( s ) ) ;
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
std : : cout < < " deflation 4.4: " < < i < < " , " < < j < < " -> " < < c < < " " < < s < < " " < < r < < " ; "
< < m_computed ( firstColm + i - 1 , firstColm ) < < " "
< < m_computed ( firstColm + i , firstColm ) < < " "
< < m_computed ( firstColm + i + 1 , firstColm ) < < " "
< < m_computed ( firstColm + i + 2 , firstColm ) < < " \n " ;
std : : cout < < m_computed ( firstColm + i - 1 , firstColm + i - 1 ) < < " "
< < m_computed ( firstColm + i , firstColm + i ) < < " "
< < m_computed ( firstColm + i + 1 , firstColm + i + 1 ) < < " "
< < m_computed ( firstColm + i + 2 , firstColm + i + 2 ) < < " \n " ;
# endif
2017-06-09 15:45:49 +02:00
if ( r = = Literal ( 0 ) )
2014-09-03 10:15:24 +02:00
{
2013-06-19 00:03:27 +02:00
m_computed ( firstColm + i , firstColm + i ) = m_computed ( firstColm + j , firstColm + j ) ;
return ;
}
c / = r ;
s / = r ;
m_computed ( firstColm + i , firstColm ) = r ;
2014-10-15 15:21:12 +02:00
m_computed ( firstColm + j , firstColm + j ) = m_computed ( firstColm + i , firstColm + i ) ;
2017-06-09 15:45:49 +02:00
m_computed ( firstColm + j , firstColm ) = Literal ( 0 ) ;
2014-09-22 15:22:52 +02:00
2014-10-15 11:59:21 +02:00
JacobiRotation < RealScalar > J ( c , - s ) ;
if ( m_compU ) m_naiveU . middleRows ( firstColu , size + 1 ) . applyOnTheRight ( firstColu + i , firstColu + j , J ) ;
else m_naiveU . applyOnTheRight ( firstColu + i , firstColu + j , J ) ;
if ( m_compV ) m_naiveV . middleRows ( firstRowW , size ) . applyOnTheRight ( firstColW + i , firstColW + j , J ) ;
2013-06-19 00:03:27 +02:00
} // end deflation 44
2013-08-20 14:10:55 +01:00
// acts on block from (firstCol+shift, firstCol+shift) to (lastCol+shift, lastCol+shift) [inclusive]
2013-06-19 00:03:27 +02:00
template < typename MatrixType >
2014-09-03 10:15:24 +02:00
void BDCSVD < MatrixType > : : deflation ( Index firstCol , Index lastCol , Index k , Index firstRowW , Index firstColW , Index shift )
{
2013-08-27 15:30:11 +01:00
using std : : sqrt ;
2014-09-03 10:15:24 +02:00
using std : : abs ;
2013-06-19 00:03:27 +02:00
const Index length = lastCol + 1 - firstCol ;
2014-09-22 15:22:52 +02:00
2014-10-15 11:59:21 +02:00
Block < MatrixXr , Dynamic , 1 > col0 ( m_computed , firstCol + shift , firstCol + shift , length , 1 ) ;
Diagonal < MatrixXr > fulldiag ( m_computed ) ;
VectorBlock < Diagonal < MatrixXr > , Dynamic > diag ( fulldiag , firstCol + shift , length ) ;
2016-05-03 23:15:29 +02:00
const RealScalar considerZero = ( std : : numeric_limits < RealScalar > : : min ) ( ) ;
2014-10-15 11:59:21 +02:00
RealScalar maxDiag = diag . tail ( ( std : : max ) ( Index ( 1 ) , length - 1 ) ) . cwiseAbs ( ) . maxCoeff ( ) ;
2016-07-25 12:35:10 +02:00
RealScalar epsilon_strict = numext : : maxi < RealScalar > ( considerZero , NumTraits < RealScalar > : : epsilon ( ) * maxDiag ) ;
2017-06-09 15:45:49 +02:00
RealScalar epsilon_coarse = Literal ( 8 ) * NumTraits < RealScalar > : : epsilon ( ) * numext : : maxi < RealScalar > ( col0 . cwiseAbs ( ) . maxCoeff ( ) , maxDiag ) ;
2014-10-15 11:59:21 +02:00
2014-09-22 15:22:52 +02:00
# ifdef EIGEN_BDCSVD_SANITY_CHECKS
assert ( m_naiveU . allFinite ( ) ) ;
assert ( m_naiveV . allFinite ( ) ) ;
assert ( m_computed . allFinite ( ) ) ;
# endif
2014-10-15 11:59:21 +02:00
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
std : : cout < < " \n deflate: " < < diag . head ( k + 1 ) . transpose ( ) < < " | " < < diag . segment ( k + 1 , length - k - 1 ) . transpose ( ) < < " \n " ;
# endif
2014-09-22 15:22:52 +02:00
//condition 4.1
2014-10-15 11:59:21 +02:00
if ( diag ( 0 ) < epsilon_coarse )
2014-09-22 15:22:52 +02:00
{
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
2014-10-15 11:59:21 +02:00
std : : cout < < " deflation 4.1, because " < < diag ( 0 ) < < " < " < < epsilon_coarse < < " \n " ;
2014-09-22 15:22:52 +02:00
# endif
2014-10-15 11:59:21 +02:00
diag ( 0 ) = epsilon_coarse ;
2014-09-22 15:22:52 +02:00
}
2013-08-20 14:10:55 +01:00
2013-06-19 00:03:27 +02:00
//condition 4.2
2014-09-22 15:22:52 +02:00
for ( Index i = 1 ; i < length ; + + i )
2014-10-15 11:59:21 +02:00
if ( abs ( col0 ( i ) ) < epsilon_strict )
2014-09-22 15:22:52 +02:00
{
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
2014-10-15 11:59:21 +02:00
std : : cout < < " deflation 4.2, set z( " < < i < < " ) to zero because " < < abs ( col0 ( i ) ) < < " < " < < epsilon_strict < < " (diag( " < < i < < " )= " < < diag ( i ) < < " ) \n " ;
2014-09-22 15:22:52 +02:00
# endif
2017-06-09 15:45:49 +02:00
col0 ( i ) = Literal ( 0 ) ;
2014-09-22 15:22:52 +02:00
}
2013-06-19 00:03:27 +02:00
//condition 4.3
2014-09-22 15:22:52 +02:00
for ( Index i = 1 ; i < length ; i + + )
2014-10-15 11:59:21 +02:00
if ( diag ( i ) < epsilon_coarse )
2014-09-22 15:22:52 +02:00
{
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
2014-10-15 11:59:21 +02:00
std : : cout < < " deflation 4.3, cancel z( " < < i < < " )= " < < col0 ( i ) < < " because diag( " < < i < < " )= " < < diag ( i ) < < " < " < < epsilon_coarse < < " \n " ;
2014-09-22 15:22:52 +02:00
# endif
2013-06-19 00:03:27 +02:00
deflation43 ( firstCol , shift , i , length ) ;
2014-09-22 15:22:52 +02:00
}
2014-10-09 23:29:01 +02:00
2014-09-22 15:22:52 +02:00
# ifdef EIGEN_BDCSVD_SANITY_CHECKS
assert ( m_naiveU . allFinite ( ) ) ;
assert ( m_naiveV . allFinite ( ) ) ;
assert ( m_computed . allFinite ( ) ) ;
# endif
2014-10-15 11:59:21 +02:00
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
std : : cout < < " to be sorted: " < < diag . transpose ( ) < < " \n \n " ;
# endif
2014-09-03 10:15:24 +02:00
{
2014-10-15 11:59:21 +02:00
// Check for total deflation
// If we have a total deflation, then we have to consider col0(0)==diag(0) as a singular value during sorting
2016-05-03 23:15:29 +02:00
bool total_deflation = ( col0 . tail ( length - 1 ) . array ( ) < considerZero ) . all ( ) ;
2014-10-15 11:59:21 +02:00
2014-09-22 15:22:52 +02:00
// Sort the diagonal entries, since diag(1:k-1) and diag(k:length) are already sorted, let's do a sorted merge.
// First, compute the respective permutation.
2015-03-31 22:54:47 +02:00
Index * permutation = m_workspaceI . data ( ) ;
2014-09-22 15:22:52 +02:00
{
permutation [ 0 ] = 0 ;
Index p = 1 ;
2014-10-15 11:59:21 +02:00
// Move deflated diagonal entries at the end.
2014-09-22 15:22:52 +02:00
for ( Index i = 1 ; i < length ; + + i )
2016-05-03 23:15:29 +02:00
if ( abs ( diag ( i ) ) < considerZero )
2014-09-22 15:22:52 +02:00
permutation [ p + + ] = i ;
Index i = 1 , j = k + 1 ;
for ( ; p < length ; + + p )
{
if ( i > k ) permutation [ p ] = j + + ;
else if ( j > = length ) permutation [ p ] = i + + ;
else if ( diag ( i ) < diag ( j ) ) permutation [ p ] = j + + ;
else permutation [ p ] = i + + ;
}
}
2013-06-19 00:03:27 +02:00
2014-10-15 11:59:21 +02:00
// If we have a total deflation, then we have to insert diag(0) at the right place
if ( total_deflation )
{
for ( Index i = 1 ; i < length ; + + i )
{
Index pi = permutation [ i ] ;
2016-05-03 23:15:29 +02:00
if ( abs ( diag ( pi ) ) < considerZero | | diag ( 0 ) < diag ( pi ) )
2014-10-15 11:59:21 +02:00
permutation [ i - 1 ] = permutation [ i ] ;
else
{
permutation [ i - 1 ] = 0 ;
break ;
}
}
}
2014-09-22 15:22:52 +02:00
// Current index of each col, and current column of each index
2015-03-31 22:54:47 +02:00
Index * realInd = m_workspaceI . data ( ) + length ;
Index * realCol = m_workspaceI . data ( ) + 2 * length ;
2013-06-19 00:03:27 +02:00
2014-09-22 15:22:52 +02:00
for ( int pos = 0 ; pos < length ; pos + + )
2013-06-19 00:03:27 +02:00
{
2014-09-22 15:22:52 +02:00
realCol [ pos ] = pos ;
realInd [ pos ] = pos ;
2013-06-19 00:03:27 +02:00
}
2014-09-22 15:22:52 +02:00
2014-10-15 11:59:21 +02:00
for ( Index i = total_deflation ? 0 : 1 ; i < length ; i + + )
2014-09-03 10:15:24 +02:00
{
2014-10-15 11:59:21 +02:00
const Index pi = permutation [ length - ( total_deflation ? i + 1 : i ) ] ;
2014-09-22 15:22:52 +02:00
const Index J = realCol [ pi ] ;
using std : : swap ;
2014-10-15 11:59:21 +02:00
// swap diagonal and first column entries:
2014-09-22 15:22:52 +02:00
swap ( diag ( i ) , diag ( J ) ) ;
2014-10-15 11:59:21 +02:00
if ( i ! = 0 & & J ! = 0 ) swap ( col0 ( i ) , col0 ( J ) ) ;
2014-09-22 15:22:52 +02:00
// change columns
if ( m_compU ) m_naiveU . col ( firstCol + i ) . segment ( firstCol , length + 1 ) . swap ( m_naiveU . col ( firstCol + J ) . segment ( firstCol , length + 1 ) ) ;
else m_naiveU . col ( firstCol + i ) . segment ( 0 , 2 ) . swap ( m_naiveU . col ( firstCol + J ) . segment ( 0 , 2 ) ) ;
if ( m_compV ) m_naiveV . col ( firstColW + i ) . segment ( firstRowW , length ) . swap ( m_naiveV . col ( firstColW + J ) . segment ( firstRowW , length ) ) ;
//update real pos
const Index realI = realInd [ i ] ;
realCol [ realI ] = J ;
realCol [ pi ] = i ;
realInd [ J ] = realI ;
realInd [ i ] = pi ;
2013-06-19 00:03:27 +02:00
}
}
2014-10-15 11:59:21 +02:00
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
std : : cout < < " sorted: " < < diag . transpose ( ) . format ( bdcsvdfmt ) < < " \n " ;
std : : cout < < " : " < < col0 . transpose ( ) < < " \n \n " ;
2014-09-22 15:22:52 +02:00
# endif
2014-10-15 11:59:21 +02:00
2014-09-22 15:22:52 +02:00
//condition 4.4
2014-10-15 11:59:21 +02:00
{
Index i = length - 1 ;
2016-05-03 23:15:29 +02:00
while ( i > 0 & & ( abs ( diag ( i ) ) < considerZero | | abs ( col0 ( i ) ) < considerZero ) ) - - i ;
2014-10-15 11:59:21 +02:00
for ( ; i > 1 ; - - i )
2014-10-15 15:21:12 +02:00
if ( ( diag ( i ) - diag ( i - 1 ) ) < NumTraits < RealScalar > : : epsilon ( ) * maxDiag )
2014-10-15 11:59:21 +02:00
{
2014-09-22 15:22:52 +02:00
# ifdef EIGEN_BDCSVD_DEBUG_VERBOSE
2014-10-15 11:59:21 +02:00
std : : cout < < " deflation 4.4 with i = " < < i < < " because " < < ( diag ( i ) - diag ( i - 1 ) ) < < " < " < < NumTraits < RealScalar > : : epsilon ( ) * diag ( i ) < < " \n " ;
# endif
eigen_internal_assert ( abs ( diag ( i ) - diag ( i - 1 ) ) < epsilon_coarse & & " diagonal entries are not properly sorted " ) ;
deflation44 ( firstCol , firstCol + shift , firstRowW , firstColW , i - 1 , i , length ) ;
}
}
# ifdef EIGEN_BDCSVD_SANITY_CHECKS
for ( Index j = 2 ; j < length ; + + j )
2016-05-03 23:15:29 +02:00
assert ( diag ( j - 1 ) < = diag ( j ) | | abs ( diag ( j ) ) < considerZero ) ;
2014-09-22 15:22:52 +02:00
# endif
# ifdef EIGEN_BDCSVD_SANITY_CHECKS
assert ( m_naiveU . allFinite ( ) ) ;
assert ( m_naiveV . allFinite ( ) ) ;
assert ( m_computed . allFinite ( ) ) ;
# endif
2013-06-19 00:03:27 +02:00
} //end deflation
2014-11-26 22:29:29 +01:00
# ifndef __CUDACC__
2014-10-29 11:29:33 +01:00
/** \svd_module
*
* \ return the singular value decomposition of \ c * this computed by Divide & Conquer algorithm
*
* \ sa class BDCSVD
*/
2013-06-19 00:03:27 +02:00
template < typename Derived >
BDCSVD < typename MatrixBase < Derived > : : PlainObject >
MatrixBase < Derived > : : bdcSvd ( unsigned int computationOptions ) const
{
return BDCSVD < PlainObject > ( * this , computationOptions ) ;
}
2014-11-26 22:29:29 +01:00
# endif
2013-06-19 00:03:27 +02:00
} // end namespace Eigen
# endif