LTI-Lib latest version v1.9 - last update 10 Apr 2010

ltiSVD.h

00001 /*
00002  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006
00003  * Lehrstuhl fuer Technische Informatik, RWTH-Aachen, Germany
00004  *
00005  * This file is part of the LTI-Computer Vision Library (LTI-Lib)
00006  *
00007  * The LTI-Lib is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License (LGPL)
00009  * as published by the Free Software Foundation; either version 2.1 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * The LTI-Lib is distributed in the hope that it will be
00013  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
00014  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with the LTI-Lib; see the file LICENSE.  If
00019  * not, write to the Free Software Foundation, Inc., 59 Temple Place -
00020  * Suite 330, Boston, MA 02111-1307, USA.
00021  */
00022 
00023 
00024 /*----------------------------------------------------------------
00025  * project ....: LTI Digital Image/Signal Processing Library
00026  * file .......: ltiSVD.h
00027  * authors ....: Xin Gu
00028  * organization: LTI, RWTH Aachen
00029  * creation ...: 11.01.01
00030  * revisions ..: $Id: ltiSVD.h,v 1.8 2006/02/07 20:34:12 ltilib Exp $
00031  */
00032 
00033 #ifndef LTI_SINGULAR_VALUE_DECOMPOSITION
00034 #define LTI_SINGULAR_VALUE_DECOMPOSITION
00035 
00036 #include "ltiMath.h"
00037 #include "ltiMatrix.h"
00038 #include "ltiLinearAlgebraFunctor.h"
00039 
00040 namespace lti {
00041 
00042   /**
00043    * Singular Value Decomposition.
00044    *
00045    * The functor will take a matrix A and compute its singular value
00046    * decomposition, consisting of three matrices U, W, and V, with
00047    * A=U*W*V' (where V' denotes the transpose of V). U is a
00048    * column-orthonormal matrix, W is a diagonal matrix with the
00049    * singular values on the diagonal, and V is a orthonormal
00050    * matrix. Those columns of V whose corresponding entries in W are
00051    * zero are the basis of A's null space.
00052    *
00053    * You can find more theoretical information about a similar
00054    * algorithm in W. H. Press, S. A. Teukolsky, W. T. Vetterling, and
00055    * B. P. Flannery: Numerical Recipes in C, 2nd edition, Cambridge
00056    * University Press, 1992.
00057    *
00058    * Only instantiations of floating point types makes sense (i.e. for
00059    * T double or float). If you want the singular values and
00060    * corresponding singular vectors to be sorted, you have to set
00061    * parameters::sort to true.
00062    */
00063   template<class T>
00064   class singularValueDecomp: public linearAlgebraFunctor {
00065   public:
00066 
00067     /**
00068      * the parameters for the class
00069      */
00070     class parameters : public linearAlgebraFunctor::parameters {
00071     public:
00072       /**
00073        * default constructor
00074        */
00075       parameters() : linearAlgebraFunctor::parameters() {
00076         sort = false;
00077         transposeU = false;
00078         transposeV = false;       
00079       };
00080 
00081       /**
00082        * copy constructor
00083        * @param other the parameters object to be copied
00084        */
00085       parameters(const parameters& other) 
00086         : linearAlgebraFunctor::parameters() {
00087         copy(other);
00088       };
00089 
00090       /**
00091        * destructor
00092        */
00093       ~parameters() {
00094       };
00095 
00096       /**
00097        * returns name of this type
00098        */
00099       const char* getTypeName() const {
00100         return "singularValueDecomp::parameters";
00101       };
00102 
00103       /**
00104        * copy the contents of a parameters object
00105        * @param other the parameters object to be copied
00106        * @return a reference to this parameters object
00107        */
00108       parameters& copy(const parameters& other)  {
00109 #     ifndef _LTI_MSC_6
00110         // MS Visual C++ 6 is not able to compile this...
00111         linearAlgebraFunctor::parameters::copy(other);
00112 #     else
00113         // ...so we have to use this workaround.
00114         // Conditional on that, copy may not be virtual.
00115         functor::parameters&
00116           (functor::parameters::* p_copy)
00117           (const functor::parameters&) =
00118           functor::parameters::copy;
00119         (this->*p_copy)(other);
00120 #     endif
00121 
00122         sort=other.sort;
00123         transposeU = other.transposeU;
00124         transposeV = other.transposeV;
00125 
00126         return *this;
00127       };
00128 
00129       /**
00130        * Assigns the contents of the other object to this object
00131        */
00132       inline parameters& operator=(const parameters& other) {
00133         copy(other);
00134         return *this;
00135       }
00136 
00137       /**
00138        * returns a pointer to a clone of the parameters
00139        */
00140       virtual functor::parameters* clone() const {
00141         return new parameters(*this);
00142       };
00143 
00144 
00145 #     ifndef _LTI_MSC_6
00146       /**
00147        * read the parameters from the given ioHandler
00148        * @param handler the ioHandler to be used
00149        * @param complete if true (the default) the enclosing begin/end will
00150        *        be also read, otherwise only the data block will be read.
00151        * @return true if write was successful
00152        */
00153       virtual bool read(ioHandler &handler, const bool complete=true)
00154 #     else
00155       bool readMS(ioHandler& handler,const bool complete=true)
00156 #     endif
00157       {
00158         bool b=true;
00159 
00160         if (complete) {
00161           b=handler.readBegin();
00162         }
00163 
00164         if (b) {
00165           lti::read(handler,"sort",this->sort);
00166           lti::read(handler,"transposeU",transposeU);
00167           lti::read(handler,"transposeV",transposeV);
00168         }
00169 
00170 #     ifndef _LTI_MSC_6
00171         // This is the standard C++ code, which MS Visual C++ 6 is not
00172         // able to compile...
00173         b = b && linearAlgebraFunctor::parameters::read(handler,false);
00174 #     else
00175         bool (functor::parameters::* p_readMS)(ioHandler&,const bool) =
00176           functor::parameters::readMS;
00177         b = b && (this->*p_readMS)(handler,false);
00178 #     endif
00179 
00180         if (complete) {
00181           b=b && handler.readEnd();
00182         }
00183 
00184         return b;
00185       }
00186 
00187 #     ifdef _LTI_MSC_6
00188       /**
00189        * read the parameters from the given ioHandler
00190        * @param handler the ioHandler to be used
00191        * @param complete if true (the default) the enclosing begin/end will
00192        *        be also read, otherwise only the data block will be read.
00193        * @return true if write was successful
00194        */
00195       virtual bool read(ioHandler& handler,const bool complete=true) {
00196         // ...we need this workaround to cope with another really awful MSVC
00197         // bug.
00198         return readMS(handler,complete);
00199       }
00200 #     endif
00201 
00202 #     ifndef _LTI_MSC_6
00203       /**
00204        * write the parameters in the given ioHandler
00205        * @param handler the ioHandler to be used
00206        * @param complete if true (the default) the enclosing begin/end will
00207        *        be also written, otherwise only the data block will be
00208        *        written.
00209        * @return true if write was successful
00210        */
00211       virtual bool write(ioHandler& handler,const bool complete=true) const
00212 #     else
00213       bool writeMS(ioHandler& handler,const bool complete=true) const
00214 #     endif
00215       {
00216         bool b=true;
00217 
00218         if (complete) {
00219           b=handler.writeBegin();
00220         }
00221 
00222         if (b) {
00223           lti::write(handler,"sort",this->sort);
00224           lti::write(handler,"transposeU",transposeU);
00225           lti::write(handler,"transposeV",transposeV);
00226         }
00227 
00228 #       ifndef _LTI_MSC_6
00229         // This is the standard C++ code, which MS Visual C++ 6 is not
00230         // able to compile...
00231         b = b && linearAlgebraFunctor::parameters::write(handler,false);
00232 #       else
00233         bool
00234         (functor::parameters::* p_writeMS)(ioHandler&,const bool) const =
00235           functor::parameters::writeMS;
00236         b = b && (this->*p_writeMS)(handler,false);
00237 #       endif
00238 
00239         if (complete) {
00240           b=b && handler.writeEnd();
00241         }
00242 
00243         return b;
00244       }
00245 
00246 #     ifdef _LTI_MSC_6
00247       /**
00248        * write the parameters to the given ioHandler
00249        * @param handler the ioHandler to be used
00250        * @param complete if true (the default) the enclosing begin/end will
00251        *        be also writen, otherwise only the data block will be writen.
00252        * @return true if write was successful
00253        */
00254       virtual bool write(ioHandler& handler,const bool complete=true) {
00255         // ...we need this workaround to cope with another really awful MSVC
00256         // bug.
00257         return writeMS(handler,complete);
00258       }
00259 #     endif
00260 
00261 
00262       // ---------------------------------------------------
00263       // the parameters
00264       // ---------------------------------------------------
00265 
00266       /**
00267        * If true, singular values and corresponding singular vectors
00268        * are rearranged so that singular values have descending
00269        * order. Default is false.
00270        */
00271       bool sort;
00272 
00273       /**
00274        * Specifies whether U (false) or Ut (true) is returned. It is
00275        * faster to return Ut. Default is false, ie U.
00276        */
00277       bool transposeU;
00278 
00279       /**
00280        * Specifies whether V (false) or Vt (true) is returned. It is
00281        * faster to return V. Default is false, ie V.
00282        */
00283       bool transposeV;
00284     };
00285 
00286     /**
00287      * default constructor
00288      */
00289     singularValueDecomp();
00290 
00291     /**
00292      * default constructor with parameters
00293      */
00294     singularValueDecomp(const parameters& params);
00295 
00296     /**
00297      * constructor. Sets parameters::sort to the given value.
00298      */
00299     singularValueDecomp(bool sort);
00300 
00301     /**
00302      * copy constructor
00303      */
00304     singularValueDecomp(const singularValueDecomp<T>& other);
00305 
00306     /**
00307      * destructor
00308      */
00309     virtual ~singularValueDecomp();
00310 
00311     /**
00312      * returns the name of this type ("singularValueDecomp")
00313      */
00314     virtual const char* getTypeName() const;
00315 
00316     /**
00317      * copy data of "other" functor.
00318      * @param other the functor to be copied
00319      * @return a reference to this functor object
00320      */
00321     singularValueDecomp& copy(const singularValueDecomp& other);
00322 
00323     /**
00324      * returns a pointer to a clone of this functor.
00325      */
00326     virtual functor* clone() const;
00327 
00328     /**
00329      * returns used parameters
00330      */
00331     const parameters& getParameters() const;
00332 
00333     /**
00334      * OnPlace version of Singular Value Decomposition. Singular Value
00335      * Decomposition means that a m*n-matrix A is decomposed into three
00336      * matrices U,W,V, such that  A = U*W*V'. U is m*n, W is a diagonal
00337      * matrix with n elements (which is implemented as vector), V is a
00338      * n*n-matrix. Note that the function returns V, not V'.
00339      * @param src matrix<T> with the source matrix, will also contain
00340      *            the U matrix after the function has returned. If
00341      *            src is a m*n matrix, U will also be of size m*n
00342      * @param w vector<T> with the singular values, sorted descendingly
00343      *                    The elements of this vector constitute the diagonal
00344      *                    of the W matrix.
00345      * @param v the V matrix
00346      * @return true is the decomposition was successfull, false if an
00347      *         error occured
00348      */
00349     bool decomposition(matrix<T>& src, vector<T>& w, matrix<T>& v) const;
00350 
00351     /**
00352      * OnPlace version of Singular Value Decomposition.
00353      * @param src matrix<T> with the source matrix, will also contain
00354      *            the U matrix after the function has returned.
00355      * @param w vector<T> with the singular values, sorted descendingly if
00356      *                    parameters::sort is true.
00357      *                    The elements of this vector constitute the diagonal
00358      *                    of the W matrix.
00359      * @param v the V matrix
00360      * @return true is the decomposition was successfull, false if an
00361      *         error occured
00362      */
00363     virtual bool apply(matrix<T>& src, vector<T>& w, matrix<T>& v) const;
00364 
00365     /**
00366      * OnCopy version of Singular Value Decomposition.
00367      * @param src matrix<T> with the source matrix
00368      * @param u the U matrix
00369      * @param w vector<T> with the singular values, sorted descendingly if
00370      *                    parameters::sort is true.
00371      *                    The elements of this vector constitute the diagonal
00372      *                    of the W matrix.
00373      * @param v the V matrix
00374      * @return true is the decomposition was successfull, false if an
00375      *         error occured
00376      */
00377     virtual bool apply(const matrix<T>& src, matrix<T>& u,
00378                        vector<T>& w, matrix<T>& v) const;
00379 
00380   private:
00381     /**
00382      * help method:(a^2+b^2)^0.5 without destructive underflow or overflow
00383      */
00384     T pythag(const T a,const T b) const;
00385 
00386     /**
00387      * sign
00388      */
00389     inline T sign(const T a,const T b) const {
00390       return (b >= T(0)) ? abs(a) : -abs(a);
00391     }
00392 
00393     /**
00394      * check if the given number is zero
00395      */
00396     inline bool isZero(const T x) const;
00397 
00398     /**
00399      * check if the given number is not zero
00400      */
00401     inline bool notZero(const T x) const;
00402 
00403     /**
00404      * sort singular values in w, and permute matrices u and v
00405      * correspondingly
00406      */
00407 //     void sort(matrix<T>& u, vector<T>& w, matrix<T>& v) const;
00408 
00409     /**
00410      * swap columns i and j in both matrices, u and v
00411      */
00412 //     void swapColumns(matrix<T>& u, matrix<T>& v, int& i,int& j) const;
00413 
00414     /**
00415      * Compute the dot product of a part of two matrix rows
00416      */
00417     inline T dotOfRows(const matrix<T>& data,
00418                        const int row1, const int row2,
00419                        int lowCol=0, const int highCol=MaxInt32) const {
00420 
00421 
00422       T sum=T(0);
00423       const vector<T>& rtmp1=data.getRow(row1);
00424       const vector<T>& rtmp2=data.getRow(row2);
00425       const typename vector<T>::const_iterator ie1=rtmp1.end();
00426       const typename vector<T>::const_iterator ie2=rtmp2.end();
00427 
00428       typename vector<T>::const_iterator i1=rtmp1.begin();
00429       typename vector<T>::const_iterator i2=rtmp2.begin();
00430 
00431       i1+=lowCol;
00432       i2+=lowCol;
00433 
00434       while (lowCol++ <= highCol && i1 != ie1 && i2 != ie2) {
00435         sum+=*i1++**i2++;
00436       }
00437       return sum;
00438     }
00439 
00440     /**
00441      * Compute the dot product of a part of two matrix columns
00442      */
00443     inline T dotOfColumns(const matrix<T>& data,
00444                           const int col1, const int col2,
00445                           int lowRow=0, int highRow=MaxInt32) const {
00446       T sum=T(0);
00447       highRow=min(highRow,data.rows()-1);
00448       while (lowRow <= highRow) {
00449         sum+=data.at(lowRow,col1)*data.at(lowRow,col2);
00450         lowRow++;
00451       }
00452       return sum;
00453     }
00454 
00455 
00456     /**
00457      * Compute the sum of a part of a matrix row
00458      */
00459     inline T sumOfRowPart(const matrix<T>& data,
00460                           const int row,
00461                           int lowCol=0, const int highCol=MaxInt32) const {
00462       T sum=T(0);
00463       const vector<T>& rtmp=data.getRow(row);
00464       const typename vector<T>::const_iterator ie=rtmp.end();
00465 
00466       typename vector<T>::const_iterator i=rtmp.begin();
00467       i+=lowCol;
00468       while (lowCol++ <= highCol && i != ie) {
00469         sum+=*i++;
00470       }
00471       return sum;
00472     }
00473 
00474     /**
00475      * Compute the sum of a part of a matrix column
00476      */
00477     inline T sumOfColumnPart(const matrix<T>& data,
00478                              const int col,
00479                              int lowRow=0, int highRow=MaxInt32) const {
00480       T sum=T(0);
00481       highRow=min(highRow,data.rows()-1);
00482       while (lowRow <= highRow) {
00483         sum+=data.at(lowRow,col);
00484         lowRow++;
00485       }
00486       return sum;
00487     }
00488 
00489 
00490     /**
00491      * Compute the sum of the absolute value of a part of a matrix row
00492      */
00493     inline T sumOfAbsRowPart(const matrix<T>& data,
00494                           const int row,
00495                           int lowCol=0, const int highCol=MaxInt32) const {
00496       T sum=T(0);
00497       const vector<T>& rtmp=data.getRow(row);
00498       const typename vector<T>::const_iterator ie=rtmp.end();
00499 
00500       typename vector<T>::const_iterator i=rtmp.begin();
00501       i+=lowCol;
00502       while (lowCol <= highCol && i != ie) {
00503         sum+=abs(*i++);
00504         lowCol++;
00505       }
00506       return sum;
00507     }
00508 
00509     /**
00510      * Compute the sum of the absolute values of a part of a matrix column
00511      */
00512     inline T sumOfAbsColumnPart(const matrix<T>& data,
00513                              const int col,
00514                              int lowRow=0, int highRow=MaxInt32) const {
00515       T sum=T(0);
00516       highRow=min(highRow,data.rows()-1);
00517       while (lowRow <= highRow) {
00518         sum+=abs(data.at(lowRow,col));
00519         lowRow++;
00520       }
00521       return sum;
00522     }
00523 
00524     inline void multiplyColumn(matrix<T>& data, const int col, const T factor,
00525                                int lowRow=0, int highRow=MaxInt32) const {
00526       highRow=min(highRow,data.rows()-1);
00527       for (int i=lowRow; i<=highRow; i++) {
00528         data.at(lowRow++,col)*=factor;
00529       }
00530     }
00531 
00532     inline void multiplyRow(matrix<T>& data, const int row, const T factor,
00533                             int lowCol=0, const int highCol=MaxInt32) const {
00534       vector<T>& rtmp=data.getRow(row);
00535       typename vector<T>::iterator i=rtmp.begin();
00536       const typename vector<T>::iterator ie=rtmp.end();
00537       i+=lowCol;
00538       while (lowCol++ <= highCol && i != ie) {
00539         *i++*=factor;
00540       }
00541     }
00542 
00543     inline void fillColumn(matrix<T>& data, const int col, const T value,
00544                                int lowRow=0, int highRow=MaxInt32) const {
00545       highRow=min(highRow,data.rows()-1);
00546       for (int i=lowRow; i<=highRow; i++) {
00547         data.at(lowRow++,col)=value;
00548       }
00549     }
00550 
00551     inline void fillRow(matrix<T>& data, const int row, const T value,
00552                         int lowCol=0, const int highCol=MaxInt32) const {
00553       vector<T>& rtmp=data.getRow(row);
00554       typename vector<T>::iterator i=rtmp.begin();
00555       const typename vector<T>::iterator ie=rtmp.end();
00556       i+=lowCol;
00557       while (lowCol++ <= highCol && i != ie) {
00558         *i++=value;
00559       }
00560     }
00561 
00562   };
00563 }
00564 
00565 #endif

Generated on Sat Apr 10 15:26:16 2010 for LTI-Lib by Doxygen 1.6.1