TooN 2.1
|
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