TooN 2.1
SVD.h
00001 // -*- c++ -*-
00002 
00003 // Copyright (C) 2005,2009 Tom Drummond (twd20@cam.ac.uk)
00004 //
00005 // This file is part of the TooN Library.  This library is free
00006 // software; you can redistribute it and/or modify it under the
00007 // terms of the GNU General Public License as published by the
00008 // Free Software Foundation; either version 2, or (at your option)
00009 // any later version.
00010 
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU General Public License for more details.
00015 
00016 // You should have received a copy of the GNU General Public License along
00017 // with this library; see the file COPYING.  If not, write to the Free
00018 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
00019 // USA.
00020 
00021 // As a special exception, you may use this file as part of a free software
00022 // library without restriction.  Specifically, if other files instantiate
00023 // templates or use macros or inline functions from this file, or you compile
00024 // this file and link it with other files to produce an executable, this
00025 // file does not by itself cause the resulting executable to be covered by
00026 // the GNU General Public License.  This exception does not however
00027 // invalidate any other reasons why the executable file might be covered by
00028 // the GNU General Public License.
00029 
00030 #ifndef __SVD_H
00031 #define __SVD_H
00032 
00033 #include <TooN/TooN.h>
00034 #include <TooN/lapack.h>
00035 
00036 namespace TooN {
00037 
00038     // TODO - should this depend on precision?
00039 static const double condition_no=1e9; // GK HACK TO GLOBAL
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 /**
00048 @class SVD TooN/SVD.h
00049 Performs %SVD and back substitute to solve equations.
00050 Singular value decompositions are more robust than LU decompositions in the face of 
00051 singular or nearly singular matrices. They decompose a matrix (of any shape) \f$M\f$ into:
00052 \f[M = U \times D \times V^T\f]
00053 where \f$D\f$ is a diagonal matrix of positive numbers whose dimension is the minimum 
00054 of the dimensions of \f$M\f$. If \f$M\f$ is tall and thin (more rows than columns) 
00055 then \f$U\f$ has the same shape as \f$M\f$ and \f$V\f$ is square (vice-versa if \f$M\f$ 
00056 is short and fat). The columns of \f$U\f$ and the rows of \f$V\f$ are orthogonal 
00057 and of unit norm (so one of them lies in SO(N)). The inverse of \f$M\f$ (or pseudo-inverse 
00058 if \f$M\f$ is not square) is then given by
00059 \f[M^{\dagger} = V \times D^{-1} \times U^T\f]
00060  
00061 If \f$M\f$ is nearly singular then the diagonal matrix \f$D\f$ has some small values 
00062 (relative to its largest value) and these terms dominate \f$D^{-1}\f$. To deal with 
00063 this problem, the inverse is conditioned by setting a maximum ratio 
00064 between the largest and smallest values in \f$D\f$ (passed as the <code>condition</code>
00065 parameter to the various functions). Any values which are too small 
00066 are set to zero in the inverse (rather than a large number)
00067  
00068 It can be used as follows to solve the \f$M\underline{x} = \underline{c}\f$ problem as follows:
00069 @code
00070 // construct M
00071 Matrix<3> M;
00072 M[0] = makeVector(1,2,3);
00073 M[1] = makeVector(4,5,6);
00074 M[2] = makeVector(7,8.10);
00075 // construct c
00076  Vector<3> c;
00077 c = 2,3,4;
00078 // create the SVD decomposition of M
00079 SVD<3> svdM(M);
00080 // compute x = M^-1 * c
00081 Vector<3> x = svdM.backsub(c);
00082  @endcode
00083 
00084 SVD<> (= SVD<-1>) can be used to create an SVD whose size is determined at run-time.
00085 @ingroup gDecomps
00086 **/
00087 template<int Rows=Dynamic, int Cols=Rows, typename Precision=DefaultPrecision>
00088 class SVD {
00089     // this is the size of the diagonal
00090     // NB works for semi-dynamic sizes because -1 < +ve ints
00091     static const int Min_Dim = Rows<Cols?Rows:Cols;
00092     
00093 public:
00094 
00095     /// default constructor for Rows>0 and Cols>0
00096     SVD() {}
00097 
00098     /// constructor for Rows=-1 or Cols=-1 (or both)
00099     SVD(int rows, int cols)
00100         : my_copy(rows,cols),
00101           my_diagonal(std::min(rows,cols)),
00102           my_square(std::min(rows,cols), std::min(rows,cols))
00103     {}
00104 
00105     /// Construct the %SVD decomposition of a matrix. This initialises the class, and
00106     /// performs the decomposition immediately.
00107     template <int R2, int C2, typename P2, typename B2>
00108     SVD(const Matrix<R2,C2,P2,B2>& m)
00109         : my_copy(m),
00110           my_diagonal(std::min(m.num_rows(),m.num_cols())),
00111           my_square(std::min(m.num_rows(),m.num_cols()),std::min(m.num_rows(),m.num_cols()))
00112     {
00113         do_compute();
00114     }
00115 
00116     /// Compute the %SVD decomposition of M, typically used after the default constructor
00117     template <int R2, int C2, typename P2, typename B2>
00118     void compute(const Matrix<R2,C2,P2,B2>& m){
00119         my_copy=m;
00120         do_compute();
00121     }
00122     
00123     private:
00124     void do_compute(){
00125         Precision* const a = my_copy.my_data;
00126         int lda = my_copy.num_cols();
00127         int m = my_copy.num_cols();
00128         int n = my_copy.num_rows();
00129         Precision* const uorvt = my_square.my_data;
00130         Precision* const s = my_diagonal.my_data;
00131         int ldu;
00132         int ldvt = lda;
00133         int LWORK;
00134         int INFO;
00135         char JOBU;
00136         char JOBVT;
00137 
00138         if(is_vertical()){ // u is a
00139             JOBU='O';
00140             JOBVT='S';
00141             ldu = lda;
00142         } else { // vt is a
00143             JOBU='S';
00144             JOBVT='O';
00145             ldu = my_square.num_cols();
00146         }
00147 
00148         Precision* wk;
00149 
00150         Precision size;
00151         LWORK = -1;
00152 
00153         // arguments are scrambled because we use rowmajor and lapack uses colmajor
00154         // thus u and vt play each other's roles.
00155         gesvd_( &JOBVT, &JOBU, &m, &n, a, &lda, s, uorvt,
00156                  &ldvt, uorvt, &ldu, &size, &LWORK, &INFO);
00157     
00158         LWORK = (long int)(size);
00159         wk = new Precision[LWORK];
00160 
00161         gesvd_( &JOBVT, &JOBU, &m, &n, a, &lda, s, uorvt,
00162                  &ldvt, uorvt, &ldu, wk, &LWORK, &INFO);
00163     
00164         delete[] wk;
00165     }
00166     
00167     bool is_vertical(){ 
00168         return (my_copy.num_rows() >= my_copy.num_cols()); 
00169     }
00170 
00171     int min_dim(){ return std::min(my_copy.num_rows(), my_copy.num_cols()); }
00172     
00173     public:
00174 
00175     /// Calculate result of multiplying the (pseudo-)inverse of M by another matrix. 
00176     /// For a matrix \f$A\f$, this calculates \f$M^{\dagger}A\f$ by back substitution 
00177     /// (i.e. without explictly calculating the (pseudo-)inverse). 
00178     /// See the detailed description for a description of condition variables.
00179     template <int Rows2, int Cols2, typename P2, typename B2>
00180     Matrix<Cols,Cols2, typename Internal::MultiplyType<Precision,P2>::type >
00181     backsub(const Matrix<Rows2,Cols2,P2,B2>& rhs, const Precision condition=condition_no)
00182     {
00183         Vector<Min_Dim> inv_diag(min_dim());
00184         get_inv_diag(inv_diag,condition);
00185         return (get_VT().T() * diagmult(inv_diag, (get_U().T() * rhs)));
00186     }
00187 
00188     /// Calculate result of multiplying the (pseudo-)inverse of M by a vector. 
00189     /// For a vector \f$b\f$, this calculates \f$M^{\dagger}b\f$ by back substitution 
00190     /// (i.e. without explictly calculating the (pseudo-)inverse). 
00191     /// See the detailed description for a description of condition variables.
00192     template <int Size, typename P2, typename B2>
00193     Vector<Cols, typename Internal::MultiplyType<Precision,P2>::type >
00194     backsub(const Vector<Size,P2,B2>& rhs, const Precision condition=condition_no)
00195     {
00196         Vector<Min_Dim> inv_diag(min_dim());
00197         get_inv_diag(inv_diag,condition);
00198         return (get_VT().T() * diagmult(inv_diag, (get_U().T() * rhs)));
00199     }
00200 
00201     /// Calculate (pseudo-)inverse of the matrix. This is not usually needed: 
00202     /// if you need the inverse just to multiply it by a matrix or a vector, use 
00203     /// one of the backsub() functions, which will be faster.
00204     /// See the detailed description of the pseudo-inverse and condition variables.
00205     Matrix<Cols,Rows> get_pinv(const Precision condition = condition_no){
00206         Vector<Min_Dim> inv_diag(min_dim());
00207         get_inv_diag(inv_diag,condition);
00208         return diagmult(get_VT().T(),inv_diag) * get_U().T();
00209     }
00210 
00211     /// Calculate the product of the singular values
00212     /// for square matrices this is the determinant
00213     Precision determinant() {
00214         Precision result = my_diagonal[0];
00215         for(int i=1; i<my_diagonal.size(); i++){
00216             result *= my_diagonal[i];
00217         }
00218         return result;
00219     }
00220     
00221     /// Calculate the rank of the matrix.
00222     /// See the detailed description of the pseudo-inverse and condition variables.
00223     int rank(const Precision condition = condition_no) {
00224         if (my_diagonal[0] == 0) return 0;
00225         int result=1;
00226         for(int i=0; i<min_dim(); i++){
00227             if(my_diagonal[i] * condition <= my_diagonal[0]){
00228                 result++;
00229             }
00230         }
00231         return result;
00232     }
00233 
00234     /// Return the U matrix from the decomposition
00235     /// The size of this depends on the shape of the original matrix
00236     /// it is square if the original matrix is wide or tall if the original matrix is tall
00237     Matrix<Rows,Min_Dim,Precision,Reference::RowMajor> get_U(){
00238         if(is_vertical()){
00239             return Matrix<Rows,Min_Dim,Precision,Reference::RowMajor>
00240                 (my_copy.my_data,my_copy.num_rows(),my_copy.num_cols());
00241         } else {
00242             return Matrix<Rows,Min_Dim,Precision,Reference::RowMajor>
00243                 (my_square.my_data, my_square.num_rows(), my_square.num_cols());
00244         }
00245     }
00246 
00247     /// Return the singular values as a vector
00248     Vector<Min_Dim,Precision>& get_diagonal(){ return my_diagonal; }
00249 
00250     /// Return the VT matrix from the decomposition
00251     /// The size of this depends on the shape of the original matrix
00252     /// it is square if the original matrix is tall or wide if the original matrix is wide
00253     Matrix<Min_Dim,Cols,Precision,Reference::RowMajor> get_VT(){
00254         if(is_vertical()){
00255             return Matrix<Min_Dim,Cols,Precision,Reference::RowMajor>
00256                 (my_square.my_data, my_square.num_rows(), my_square.num_cols());
00257         } else {
00258             return Matrix<Min_Dim,Cols,Precision,Reference::RowMajor>
00259                 (my_copy.my_data,my_copy.num_rows(),my_copy.num_cols());
00260         }
00261     }
00262 
00263     ///Return the pesudo-inverse diagonal. The reciprocal of the diagonal elements
00264     ///is returned if the elements are well scaled with respect to the largest element,
00265     ///otherwise 0 is returned.
00266     ///@param inv_diag Vector in which to return the inverse diagonal.
00267     ///@param condition Elements must be larger than this factor times the largest diagonal element to be considered well scaled. 
00268     void get_inv_diag(Vector<Min_Dim>& inv_diag, const Precision condition){
00269         for(int i=0; i<min_dim(); i++){
00270             if(my_diagonal[i] * condition <= my_diagonal[0]){
00271                 inv_diag[i]=0;
00272             } else {
00273                 inv_diag[i]=static_cast<Precision>(1)/my_diagonal[i];
00274             }
00275         }
00276     }
00277 
00278 private:
00279     Matrix<Rows,Cols,Precision,RowMajor> my_copy;
00280     Vector<Min_Dim,Precision> my_diagonal;
00281     Matrix<Min_Dim,Min_Dim,Precision,RowMajor> my_square; // square matrix (U or V' depending on the shape of my_copy)
00282 };
00283 
00284 
00285 
00286 
00287 
00288 
00289 /// version of SVD forced to be square
00290 /// princiapally here to allow use in WLS
00291 /// @ingroup gDecomps
00292 template<int Size, typename Precision>
00293 struct SQSVD : public SVD<Size, Size, Precision> {
00294     ///All constructors are forwarded to SVD in a straightforward manner.
00295     ///@name Constructors
00296     ///@{
00297     SQSVD() {}
00298     SQSVD(int size) : SVD<Size,Size,Precision>(size, size) {}
00299     
00300     template <int R2, int C2, typename P2, typename B2>
00301     SQSVD(const Matrix<R2,C2,P2,B2>& m) : SVD<Size,Size,Precision>(m) {}
00302     ///@}
00303 };
00304 
00305 
00306 }
00307 
00308 
00309 #endif