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

ltiSerialPCA.h

00001 /*
00002  * Copyright (C) 2000, 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 .......: ltiPCA.h
00027  * authors ....: Jochen Wickel
00028  * organization: LTI, RWTH Aachen
00029  * creation ...: 27.11.2000
00030  * revisions ..: $Id: ltiSerialPCA.h,v 1.10 2007/09/08 20:04:04 alvarado Exp $
00031  */
00032 
00033 #ifndef _LTI_SERIAL_PCA_H_
00034 #define _LTI_SERIAL_PCA_H_
00035 
00036 #include "ltiLinearAlgebraFunctor.h"
00037 #include "ltiEigenSystem.h"
00038 #include "ltiIoHandler.h"
00039 #include "ltiSerialVectorStats.h"
00040 
00041 namespace lti {
00042   /**
00043    * Functor for sequentially computing a principal component analysis.
00044    *
00045    * It receives a set of input vectors in form of a matrix (each row of
00046    * the matrix corresponds to an input vector), which will be transformed
00047    * with PCA.
00048    *
00049    * The first time you use the apply()-method, the transformation
00050    * matrix will be computed.  You can use this transformation matrix
00051    * with other data sets using the transform() methods.
00052    *
00053    * Please note that the eigenvector matrices will contain the
00054    * eigenvector in the COLUMNS and not in the rows, as could be
00055    * expected.  This avoids the requirement of transposing matrices in
00056    * the vector transformations (see also lti::eigenSystem<T>).
00057    *
00058    * @ingroup gLinearAlgebra
00059    * \see lti::principalComponents
00060    */
00061   template <class T>
00062   class serialPCA : public linearAlgebraFunctor {
00063   public:
00064     /**
00065      * the parameters for the class serialPCA
00066      */
00067     class parameters : public linearAlgebraFunctor::parameters {
00068     public:
00069       /**
00070        * default constructor
00071        */
00072       parameters() 
00073         : linearAlgebraFunctor::parameters() {
00074         resultDim=3;
00075         autoDim=false;
00076         useCorrelation=false;
00077         whitening=false;
00078 
00079         eigen=new jacobi<T>;
00080       }
00081 
00082       /**
00083        * copy constructor
00084        * @param other the parameters object to be copied
00085        */
00086       parameters(const parameters& other) 
00087         : linearAlgebraFunctor::parameters() {
00088         eigen = 0;
00089         copy(other);
00090       }
00091 
00092 
00093       /**
00094        * destructor
00095        */
00096       ~parameters(){
00097         delete eigen;
00098       }
00099 
00100       /**
00101        * returns name of this type
00102        */
00103       const char* getTypeName() const {
00104         return "serialPCA::parameters";
00105       }
00106 
00107       /**
00108        * copy the contents of a parameters object
00109        * @param other the parameters object to be copied
00110        * @return a reference to this parameters object
00111        */
00112       parameters& copy(const parameters& other) {
00113 #     ifndef _LTI_MSC_6
00114         // MS Visual C++ 6 is not able to compile this...
00115         linearAlgebraFunctor::parameters::copy(other);
00116 #     else
00117         // ...so we have to use this workaround.
00118         // Conditional on that, copy may not be virtual.
00119         functor::parameters&
00120           (functor::parameters::* p_copy)
00121           (const functor::parameters&) =
00122           functor::parameters::copy;
00123         (this->*p_copy)(other);
00124 #     endif
00125 
00126         delete eigen;
00127         eigen = 0;
00128 
00129         resultDim=other.resultDim;
00130         autoDim=other.autoDim;
00131         useCorrelation=other.useCorrelation;
00132         whitening=other.whitening;
00133         eigen=dynamic_cast<eigenSystem<T>*>(other.eigen->clone());
00134         return *this;
00135       }
00136 
00137 
00138       /**
00139        * Assigns the contents of the other object to this object
00140        */
00141       inline parameters& operator=(const parameters& other) {
00142         copy(other);
00143         return *this;
00144       }
00145 
00146       /**
00147        * returns a pointer to a clone of the parameters
00148        */
00149       virtual functor::parameters* clone() const {
00150         return new parameters(*this);
00151       }
00152 
00153 #     ifndef _LTI_MSC_6
00154       /**
00155        * read the parameters from the given ioHandler
00156        * @param handler the ioHandler to be used
00157        * @param complete if true (the default) the enclosing begin/end will
00158        *        be also read, otherwise only the data block will be read.
00159        * @return true if write was successful
00160        */
00161       virtual bool read(ioHandler &handler, const bool complete=true)
00162 #     else
00163       bool readMS(ioHandler& handler,const bool complete=true)
00164 #     endif
00165       {
00166         bool b=true;
00167 
00168         if (complete) {
00169           b=handler.readBegin();
00170         }
00171 
00172         if (b) {
00173           lti::read(handler,"dim",resultDim);
00174           lti::read(handler,"auto",autoDim);
00175           lti::read(handler,"corr",useCorrelation);
00176           lti::read(handler,"white",whitening);
00177         }
00178 
00179 #     ifndef _LTI_MSC_6
00180         // This is the standard C++ code, which MS Visual C++ 6 is not
00181         // able to compile...
00182         b = b && linearAlgebraFunctor::parameters::read(handler,false);
00183 #     else
00184         bool (functor::parameters::* p_readMS)(ioHandler&,const bool) =
00185           functor::parameters::readMS;
00186         b = b && (this->*p_readMS)(handler,false);
00187 #     endif
00188 
00189         if (complete) {
00190           b=b && handler.readEnd();
00191         }
00192 
00193         return b;
00194       }
00195 
00196 #     ifdef _LTI_MSC_6
00197       /**
00198        * read the parameters from the given ioHandler
00199        * @param handler the ioHandler to be used
00200        * @param complete if true (the default) the enclosing begin/end will
00201        *        be also read, otherwise only the data block will be read.
00202        * @return true if write was successful
00203        */
00204       virtual bool read(ioHandler& handler,const bool complete=true) {
00205         // ...we need this workaround to cope with another really awful MSVC
00206         // bug.
00207         return readMS(handler,complete);
00208       }
00209 #     endif
00210 
00211 #     ifndef _LTI_MSC_6
00212       /**
00213        * write the parameters in the given ioHandler
00214        * @param handler the ioHandler to be used
00215        * @param complete if true (the default) the enclosing begin/end will
00216        *        be also written, otherwise only the data block will be
00217        *        written.
00218        * @return true if write was successful
00219        */
00220       virtual bool write(ioHandler& handler,const bool complete=true) const
00221 #     else
00222       bool writeMS(ioHandler& handler,const bool complete=true) const
00223 #     endif
00224       {
00225         bool b=true;
00226 
00227         if (complete) {
00228           b=handler.writeBegin();
00229         }
00230 
00231         if (b) {
00232           lti::write(handler,"dim",resultDim);
00233           lti::write(handler,"auto",autoDim);
00234           lti::write(handler,"corr",useCorrelation);
00235           lti::write(handler,"white",whitening);
00236         }
00237 
00238 #       ifndef _LTI_MSC_6
00239         // This is the standard C++ code, which MS Visual C++ 6 is not
00240         // able to compile...
00241         b = b && linearAlgebraFunctor::parameters::write(handler,false);
00242 #       else
00243         bool
00244         (functor::parameters::* p_writeMS)(ioHandler&,const bool) const =
00245           functor::parameters::writeMS;
00246         b = b && (this->*p_writeMS)(handler,false);
00247 #       endif
00248 
00249         if (complete) {
00250           b=b && handler.writeEnd();
00251         }
00252 
00253         return b;
00254       }
00255 
00256 #     ifdef _LTI_MSC_6
00257       /**
00258        * write the parameters to the given ioHandler
00259        * @param handler the ioHandler to be used
00260        * @param complete if true (the default) the enclosing begin/end will
00261        *        be also writen, otherwise only the data block will be writen.
00262        * @return true if write was successful
00263        */
00264       virtual bool write(ioHandler& handler,const bool complete=true) {
00265         // ...we need this workaround to cope with another really awful MSVC
00266         // bug.
00267         return writeMS(handler,complete);
00268       }
00269 #     endif
00270 
00271 
00272       /**
00273        * This is the dimension of the reduced vectors.
00274        *
00275        * Default value: 3
00276        */
00277       int resultDim;
00278 
00279       /**
00280        * This flag determines, if the functor should determine a
00281        * maximum allowable dimension itself. "Maximum dimension" means
00282        * that the dimension is equal to the number of eigenvalues of
00283        * the covariance matrix which are larger than zero.
00284        *
00285        * Default value: false
00286        */
00287       bool autoDim;
00288 
00289       /**
00290        * This flag determines if the functor should use the
00291        * correlation coefficient matrix (flag is true) for eigenvector
00292        * computation or the covariance matrix (flag is false).
00293        *
00294        * The default is false.
00295        */
00296       bool useCorrelation;
00297 
00298       /**
00299        * This flag determines if the functor should perform a
00300        * whitening transform of the data. Whitening means that
00301        * 1. A PCA is performed, using the covariance matrix for
00302        *    eigenvector computation
00303        * 2. A scaling of the transformed data by the inverse of the
00304        *    square root of the eigenvalues.
00305        *
00306        * You should set useCorrelation to false if you use whitening.
00307        *
00308        * The default is false.
00309        */
00310       bool whitening;
00311 
00312       /**
00313        * The eigensystem functor used for computing eigenvectors
00314        */
00315       eigenSystem<T> *eigen;
00316 
00317     };
00318 
00319     /**
00320      * default constructor
00321      */
00322     serialPCA();
00323 
00324     /**
00325      * copy constructor
00326      * @param other the object to be copied
00327      */
00328     serialPCA(const serialPCA& other);
00329 
00330     /**
00331      * destructor
00332      */
00333     virtual ~serialPCA();
00334 
00335     /**
00336      * returns the name of this type ("serialPCA")
00337      */
00338     virtual const char* getTypeName() const;
00339 
00340     /**
00341      * Consider the given data for the computation of a principal components
00342      * transformation matrix.
00343      *
00344      * You can later call the transform() method or the apply method to
00345      * transform the data.
00346      *
00347      * Each time you call this method, the current transformation matrix is
00348      * invalidated and later recomputed when you call a transform method.
00349      * Then, all data considered so far will be used in the
00350      * covariance/correlation matrix estimation.
00351      *
00352      * @param data matrix<T> with the source data.
00353      * @return true if the PCA could be computed, false otherwise
00354      */
00355     bool consider(const matrix<T>& data);
00356 
00357     /**
00358      * Consider a vector in the estimation of the covariance/correlation
00359      * matrix.
00360      *
00361      * You can later call the transform() method or the apply method to
00362      * transform the data.
00363      *
00364      * Each time you call this method, the current transformation matrix is
00365      * invalidated and later recomputed when you call a transform method.
00366      * Then, all data considered so far will be used in the
00367      * covariance/correlation matrix estimation.
00368      *
00369      * @param data matrix<T> with the source data.
00370      * @return true if the PCA could be computed, false otherwise
00371      */
00372     bool consider(const vector<T>& data);
00373     
00374     /**
00375      * Reset the data
00376      *
00377      * Removes all data considered until now and set the functor as in the
00378      * initial empty state.
00379      */
00380     bool reset();
00381     
00382 
00383     /**
00384      * Computes the principal components of the previously
00385      * considered data points and applies it to the given data
00386      * matrix. The result is the transformed matrix.
00387      * data and result must not be references to the same matrix.
00388      * This method uses the eigenvector functor given in the parameters.
00389      * By default, it uses ltilib's own jacobi functor. However, you can
00390      * speed it up considerably by using the eigensystem functor in
00391      * the lamath directory.
00392      *
00393      * \warning This method does not consider the given \a src data to compute
00394      * the transformation, unless it is the very first time you call this
00395      * functor.  The normal way of using apply() is previously having called
00396      * the \a consider() method.
00397      *
00398      * @param src matrix<T> with the source data.
00399      * @param dest matrix<T> with the result data.
00400      * @return true if the PCA could be computed, false otherwise
00401      */
00402     bool apply(const matrix<T>& src, matrix<T>& dest);
00403 
00404 
00405     /**
00406      * On-Place version of the transformation.
00407      *
00408      * Computes the principal components of the previously
00409      * considered data points and applies it to the given data
00410      * matrix. The result is the transformed matrix.
00411      * This method uses the eigenvector functor given in the parameters.
00412      * By default, it uses ltilib's own jacobi functor. However, you can
00413      * speed it up considerably by using the eigensystem functor in
00414      * the lamath directory.
00415      *
00416      * \warning This method does not consider the given \a srcdest data to
00417      * compute the transformation, unless it is the very first time you call
00418      * this functor.  The normal way of using apply() is previously having
00419      * called the \a consider() method. 
00420      *
00421      * @param srcdest matrix<T> with the source data, which will also contain
00422      * the result.  
00423      * @return a reference to <code>srcdest</code>.
00424      */
00425     bool apply(matrix<T>& srcdest);
00426 
00427     /**
00428      * Transforms a single vector according to a previously computed
00429      * transformation matrix.
00430      */
00431     inline bool apply(const vector<T> &src, vector<T>& result) {
00432       return transform(src,result);
00433     }
00434 
00435     /**
00436      * Transforms a single vector according to a previously computed
00437      * transformation matrix.
00438      * @param src the data vector
00439      * @param result the vector which will receive the transformed data
00440      * @return a reference to <code>result</code>
00441      */
00442     bool transform(const vector<T> &src, vector<T>& result);
00443 
00444     /**
00445      * Transform an entire matrix according to a previously computed
00446      * transformation matrix. Unfortunately, we must choose a name
00447      * different from apply.
00448      * @param src the data matrix
00449      * @param result the matrix which will receive the transformed data
00450      * @return a reference to <code>result</code>
00451      */
00452     bool transform(const matrix<T> &src, matrix<T>& result);
00453 
00454     /**
00455      * Returns the previously computed transform matrix.
00456      * @param result the matrix which will receive the transformation
00457      *        matrix.
00458      * @return true if the matrix could be computed, false otherwise.
00459      */
00460     bool getTransformMatrix(matrix<T>& result) const;
00461 
00462     /**
00463      * Returns the previously computed transform matrix.
00464      * @return a const reference to the last computed or used transformation
00465      *           matrix.
00466      */
00467     const matrix<T>& getTransformMatrix() const;
00468 
00469     /**
00470      * Returns the previously computed eigenvalues of the covariance
00471      * matrix.
00472      * @param result the vector which will receive the eigenvalues.
00473      * @return true if the values could be obtained, false otherwise.
00474      */
00475     bool getEigenValues(vector<T>& result) const;
00476 
00477     /**
00478      * Returns the previously computed eigenvalues of the covariance
00479      * matrix.
00480      *
00481      * @return a const reference to the last computed eigenvalues
00482      */
00483     const vector<T>& getEigenValues() const;
00484 
00485     /**
00486      * Returns the previously computed eigenvectors of the covariance
00487      * matrix.
00488      * @param result the matrix which will receive the eigenvectors.
00489      *        Each column of the matrix contains one eigenvector.
00490      * @return true if the vectors could be obtained, false otherwise
00491      */
00492     bool getEigenVectors(matrix<T>& result) const;
00493 
00494     /**
00495      * Returns the previously computed eigenvectors of the covariance
00496      * matrix.
00497      *
00498      * This method will call the normal getEigenVectors() methods and
00499      * after that will transpose the obtained matrix, i.e. it is faster
00500      * to get the eigenvectors in the columns.
00501      *
00502      * @param result the matrix which will receive the eigenvectors.
00503      *        Each row of the matrix contains one eigenvector.
00504      * @return true if the vectors could be obtained, false otherwise
00505      */
00506     bool getEigenVectorsInRows(matrix<T>& result) const;
00507 
00508 
00509     /**
00510      * Returns the previously computed eigenvectors of the covariance
00511      * matrix.
00512      * @return a const reference to the last computed eigenvectors
00513      */
00514     const matrix<T>& getEigenVectors() const;
00515 
00516     /**
00517      * Set the dimension to which the vectors should be reduced.
00518      */
00519     void setDimension(int k);
00520 
00521     /**
00522      * copy data of "other" functor.
00523      * @param other the functor to be copied
00524      * @return a reference to this functor object
00525      */
00526     serialPCA& copy(const serialPCA& other);
00527 
00528     /**
00529      * returns a pointer to a clone of this functor.
00530      */
00531     virtual functor* clone() const;
00532 
00533     /**
00534      * returns used parameters
00535      */
00536     const parameters& getParameters() const;
00537 
00538     /**
00539      * Update functor's parameters.
00540      *
00541      * Initialize some internal data according to the parameters.
00542      *
00543      * @return true if successful, false otherwise
00544      */
00545     virtual bool updateParameters();
00546 
00547     /**
00548      * Reads this functor from the given handler.
00549      */
00550     virtual bool read(ioHandler &handler, const bool complete=true);
00551 
00552     /**
00553      * Writes this functor to the given handler.
00554      */
00555     virtual bool write(ioHandler &handler, const bool complete=true) const;
00556 
00557     int getUsedDimension() const {
00558       return usedDimensionality;
00559     }
00560 
00561   protected:
00562     /**
00563      * Determines the intrinsic dimensionality of the data set if the
00564      * user specify autoDim, otherwise return parameters::resultDim.
00565      * The member usedDimensionality will be set with the returned value
00566      */
00567     int checkDim();
00568 
00569 
00570   private:
00571 
00572     bool buildTransform();
00573 
00574     matrix<T> orderedEigVec;
00575     matrix<T> transformMatrix;
00576     vector<T> eigValues;
00577 
00578     vector<T> offset;
00579     vector<T> scale;
00580     vector<T> whiteScale;
00581 
00582     /**
00583      * This attribute accumulates the statistics of data being considered.
00584      */
00585     serialVectorStats<T> vstat;
00586 
00587     /**
00588      * Flag that indicates if new data has been considered, such that the
00589      * covariance matrix needs to be recomputed, as well as its eigenvalues and
00590      * eigenvectors.
00591      */
00592     bool isValid;
00593 
00594     /**
00595      * Dimensionality of the final space being used.
00596      */
00597     int usedDimensionality;
00598   };
00599 
00600   template <class T>
00601   bool read(ioHandler& handler,
00602             serialPCA<T>& pca,
00603             const bool complete=true) {
00604     return pca.read(handler,complete);
00605   }
00606 
00607 
00608   template <class T>
00609   bool write(ioHandler& handler,
00610              const serialPCA<T>& pca,
00611              const bool complete=true) {
00612     return pca.write(handler,complete);
00613   }
00614 
00615 }
00616 
00617 #endif

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