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

ltiFastICA.h

00001 /*
00002  * Copyright (C) 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-Lib: Image Processing and Computer Vision Library
00026  * file .......: ltiFastICA.h
00027  * authors ....: Arnd Hannemann
00028  * organization: LTI, RWTH Aachen
00029  * creation ...: 3.3.2004
00030  * revisions ..: $Id: ltiFastICA.h,v 1.8 2006/02/08 12:20:58 ltilib Exp $
00031  */
00032 
00033 #ifndef _LTI_FAST_I_C_A_H_
00034 #define _LTI_FAST_I_C_A_H_
00035 
00036 #include "ltiLinearAlgebraFunctor.h"
00037 #include "ltiUniformDist.h"
00038 #include "ltiPCA.h"
00039 
00040 namespace lti {
00041   /**
00042    * This class implements a fast fixed point algorithm for the Independent
00043    * Component Analysis (ICA).
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 ICA. (apply() methods)
00048    *
00049    * If you only want to compute the transformation matrix you can use
00050    * the computeTransformMatrix() methods. 
00051    *
00052    * Once the transformationMatrix is computed (by an apply,
00053    * or computeTransformMatrix method) you can use the transform() methods to
00054    * %transform other datasets with the same transformation matrix.
00055    *
00056    * Note that you have to subtract the offset vector from data you want to 
00057    * %transform with the transformation matrix if \b not 
00058    * using the transform() methods.
00059    */
00060   template<class T>
00061   class fastICA : public linearAlgebraFunctor {
00062   public:
00063     /**
00064      * The parameters for the class fastICA
00065      */
00066     class parameters : public linearAlgebraFunctor::parameters {
00067     public:
00068 
00069       /**
00070        * Enumeration of orthogonalization methods.
00071        */
00072       enum eOrthogonalizationMethod {
00073         Deflationary, /**< The ICs are computed one after another and 
00074                        *   orthogonalization is done dependent on the
00075                        *   already computed ICs (first component has
00076                        *   a free choice of direction)
00077                        */
00078         Symmetric     /**< The ICs are computed in parallel and 
00079                        *   orthogonalization is done after each 
00080                        *   iteration step considering all ICs.
00081                        */
00082       };
00083 
00084       /**
00085        * Enumeration of negentropyApproximation methods.
00086        *
00087        * In fact the first and second derivation of the stated functions are
00088        * used in the algorithm.
00089        */
00090       enum eNegentropyApproximation {
00091         Exp, /**< using 
00092               * \f$G(x)=-\frac{1}{\alpha_{exp}}*exp(-\frac{\alpha_{exp}}{2}*u^2)
00093               * \f$ as negentropy approximation function
00094               */
00095         Tanh, /**< using
00096                * \f$G(u)=\frac{1}{\alpha_{tanh}}*log (cosh(\alpha_{tanh}*u))\f$
00097                * as negentropy approximation function
00098                */
00099         Kurt /**< using
00100               * \f$G(u)=u^4 \f$ as negentropy Approximation function
00101               */
00102       };
00103 
00104       /**
00105        * Default constructor
00106        */
00107       parameters() : linearAlgebraFunctor::parameters() {
00108         //TODO: Initialize your parameter values!
00109         // If you add more parameters manually, do not forget to do following:
00110         // 1. indicate in the default constructor the default values
00111         // 2. make sure that the copy member also copy your new parameters
00112         // 3. make sure that the read and write members also read and
00113         //    write your parameters
00114 
00115         // maxSteps
00116         // delta
00117         maxSteps = 1000;
00118         orthogonalizationMethod = Deflationary;
00119         negentropyApproximation = Exp;
00120         epsilon = static_cast<T>(0.0001f);
00121         expAlpha = 1;
00122         tanhAlpha = 1;
00123       };
00124 
00125       /**
00126        * Copy constructor
00127        * @param other the parameters object to be copied
00128        */
00129       parameters(const parameters& other) : linearAlgebraFunctor::parameters() {
00130         copy(other);
00131       }
00132       
00133       /**
00134        * Destructor
00135        */
00136       ~parameters() {
00137       };
00138 
00139       /**
00140        * Returns name of this type
00141        */
00142       const char* getTypeName() const {
00143         return "fastICA::parameters";
00144       };
00145 
00146       /**
00147        * Copy the contents of a parameters object
00148        * @param other the parameters object to be copied
00149        * @return a reference to this parameters object
00150        */
00151       parameters& copy(const parameters& other) {
00152 #     ifndef _LTI_MSC_6
00153         // MS Visual C++ 6 is not able to compile this...
00154         linearAlgebraFunctor::parameters::copy(other);
00155 #     else
00156         // ...so we have to use this workaround.
00157         // Conditional on that, copy may not be virtual.
00158         linearAlgebraFunctor::parameters& (linearAlgebraFunctor::parameters::* p_copy)
00159                             (const linearAlgebraFunctor::parameters&) =
00160                             linearAlgebraFunctor::parameters::copy;
00161         (this->*p_copy)(other);
00162 #     endif
00163 
00164         maxSteps = other.maxSteps;
00165         orthogonalizationMethod = other.orthogonalizationMethod;
00166         negentropyApproximation = other.negentropyApproximation;  
00167         expAlpha = other.expAlpha;
00168         tanhAlpha = other.tanhAlpha;      
00169         epsilon = other.epsilon;
00170         return *this;
00171       };
00172 
00173       /**
00174        * Copy the contents of a parameters object
00175        * @param other the parameters object to be copied
00176        * @return a reference to this parameters object
00177        */
00178       parameters& operator=(const parameters& other) {
00179         return copy(other);
00180       };
00181 
00182       /**
00183        * Returns a pointer to a clone of the parameters
00184        */
00185       virtual functor::parameters* clone() const {
00186         return new parameters(*this);
00187       };
00188 
00189 #     ifndef _LTI_MSC_6
00190       /**
00191        * Write the parameters in the given ioHandler
00192        * @param handler the ioHandler to be used
00193        * @param complete if true (the default) the enclosing begin/end will
00194        *        be also written, otherwise only the data block will be written.
00195        * @return true if write was successful
00196        */
00197       virtual bool write(ioHandler& handler,const bool complete=true) const
00198 #     else
00199       /**
00200        * This function is required by MSVC only, as a workaround for a
00201        * very awful bug, which exists since MSVC V.4.0, and still by
00202        * V.6.0 with all bugfixes (so called "service packs") remains
00203        * there...  This method is also public due to another bug, so please
00204        * NEVER EVER call this method directly: use write() instead
00205        */
00206       bool writeMS(ioHandler& handler,const bool complete=true) const
00207 #     endif
00208       {
00209         bool b = true;
00210         if (complete) {
00211           b = handler.writeBegin();
00212         }
00213         
00214         if (b) {
00215 
00216           std::string str1,str2;
00217           switch (orthogonalizationMethod) {
00218               case Deflationary: {
00219                 str1 = "Deflationary";
00220                 break;
00221               }
00222               case Symmetric: {
00223                 str1 = "Symmetric";
00224                 break;
00225               }
00226               default: {
00227                 str1 = "Deflationary";
00228                 break;
00229               }
00230           }
00231           switch (negentropyApproximation) {
00232               case Exp: {
00233                 str2 = "Exp";
00234                 break;
00235               }
00236               case Tanh: {
00237                 str2 = "Tanh";
00238                 break;
00239               }
00240               case Kurt: {
00241                 str2 = "Kurt";
00242                 break;
00243               }
00244           }
00245           
00246           lti::write(handler,"maxSteps",maxSteps);
00247           lti::write(handler,"epsilon",epsilon);
00248           lti::write(handler,"expAlpha",expAlpha);
00249           lti::write(handler,"tanhAlpha",tanhAlpha);
00250           lti::write(handler,"orthogonalizationMethod",str1);
00251           lti::write(handler,"negentropyApproximation",str2);
00252         }
00253 
00254 #     ifndef _LTI_MSC_6
00255         // This is the standard C++ code, which MS Visual C++ 6 is not able to
00256         // compile...
00257         b = b && linearAlgebraFunctor::parameters::write(handler,false);
00258 #     else
00259         bool (linearAlgebraFunctor::parameters::* p_writeMS)(ioHandler&,
00260                                                          const bool) const =
00261           linearAlgebraFunctor::parameters::writeMS;
00262         b = b && (this->*p_writeMS)(handler,false);
00263 #     endif
00264 
00265         if (complete) {
00266           b = b && handler.writeEnd();
00267         }
00268 
00269         return b;
00270       }
00271 
00272 #     ifdef _LTI_MSC_6
00273       /**
00274        * Write the parameters in the given ioHandler
00275        * @param handler the ioHandler to be used
00276        * @param complete if true (the default) the enclosing begin/end will
00277        *        be also written, otherwise only the data block will be written.
00278        * @return true if write was successful
00279        */
00280       bool write(ioHandler& handler,
00281                  const bool complete=true) const {
00282         // ...we need this workaround to cope with another really
00283         // awful MSVC bug.
00284         return writeMS(handler,complete);
00285       }
00286 #     endif
00287 
00288 
00289 #     ifndef _LTI_MSC_6
00290       /**
00291        * Read the parameters from the given ioHandler
00292        * @param handler the ioHandler to be used
00293        * @param complete if true (the default) the enclosing begin/end will
00294        *        be also written, otherwise only the data block will be written.
00295        * @return true if read was successful
00296        */
00297       virtual bool read(ioHandler& handler,const bool complete=true)
00298 #     else
00299       /**
00300        * This function is required by MSVC only, as a workaround for a
00301        * very awful bug, which exists since MSVC V.4.0, and still by
00302        * V.6.0 with all bugfixes (so called "service packs") remains
00303        * there...  This method is also public due to another bug, so please
00304        * NEVER EVER call this method directly: use read() instead
00305        */
00306       bool readMS(ioHandler& handler,const bool complete=true)
00307 #     endif
00308       {
00309         bool b = true;
00310         if (complete) {
00311           b = handler.readBegin();
00312         }
00313         
00314         if (b) {
00315           std::string str1,str2;
00316           lti::write(handler,"maxSteps",maxSteps);
00317           lti::write(handler,"epsilon",epsilon);
00318           lti::write(handler,"expAlpha",expAlpha);
00319           lti::write(handler,"tanhAlpha",tanhAlpha);
00320           lti::write(handler,"orthogonalizationMethod",str1);
00321           lti::write(handler,"negentropyApproximation",str2);
00322           if (str1=="Symmetric") {
00323             orthogonalizationMethod = Symmetric;
00324           } // default
00325           else {
00326             orthogonalizationMethod = Deflationary;
00327           }
00328 
00329           if (str2=="Tanh") {
00330             negentropyApproximation = Tanh;
00331           } else if (str2=="Kurt") {
00332             negentropyApproximation = Kurt;
00333           } //default
00334           else {
00335             negentropyApproximation = Exp;
00336           }
00337 
00338         }
00339 
00340 #       ifndef _LTI_MSC_6
00341         // This is the standard C++ code, which MS Visual C++ 6 is not
00342         // able to compile...
00343         b = b && linearAlgebraFunctor::parameters::read(handler,false);
00344 #       else
00345         bool (linearAlgebraFunctor::parameters::* p_readMS)(ioHandler&,
00346                                                         const bool) =
00347           linearAlgebraFunctor::parameters::readMS;
00348         b = b && (this->*p_readMS)(handler,false);
00349 #       endif
00350 
00351         if (complete) {
00352           b = b && handler.readEnd();
00353         }
00354         
00355         return b;
00356       }
00357 
00358 #     ifdef _LTI_MSC_6
00359       /**
00360        * Read the parameters from the given ioHandler
00361        * @param handler the ioHandler to be used
00362        * @param complete if true (the default) the enclosing begin/end will
00363        *        be also written, otherwise only the data block will be written.
00364        * @return true if read was successful
00365        */
00366       bool read(ioHandler& handler,const bool complete=true) {
00367         // ...we need this workaround to cope with another really awful MSVC
00368         // bug.
00369         return readMS(handler,complete);
00370       }
00371 #     endif
00372 
00373       // ------------------------------------------------
00374       // the parameters
00375       // ------------------------------------------------
00376 
00377       /**
00378        * maximum number of iterations to spend on one component
00379        *
00380        * Default: 1000
00381        */
00382       int maxSteps;
00383 
00384       /**
00385        * at which epsilon the vector is assumed to be converged
00386        *
00387        * Default: 0.0001
00388        */
00389       T epsilon;
00390 
00391       /**
00392        * orthogonalization method used
00393        *
00394        * Default: Deflationary
00395        */
00396       eOrthogonalizationMethod orthogonalizationMethod;
00397 
00398       /**
00399        * negentropy approximation
00400        *
00401        * Default: Exp
00402        */
00403       eNegentropyApproximation negentropyApproximation;
00404 
00405       /**
00406        * parameter for tuning the exponential negentropy approximation
00407        *
00408        * Default: 1
00409        */
00410       T expAlpha;
00411  
00412       /**  
00413        * parameter for tuning the tanh negentropy approximation
00414        *
00415        * Default: 1
00416        */
00417       T tanhAlpha;
00418              
00419     };
00420 
00421     /**
00422      * Default constructor
00423      */
00424     fastICA();
00425 
00426     /**
00427      * Construct a functor using the given parameters
00428      */
00429     fastICA(const parameters& par);
00430 
00431     /**
00432      * Copy constructor
00433      * @param other the object to be copied
00434      */
00435     fastICA(const fastICA& other);
00436 
00437     /**
00438      * Destructor
00439      */
00440     virtual ~fastICA();
00441 
00442     /**
00443      * Returns the name of this type ("fastICA")
00444      */
00445     virtual const char* getTypeName() const;
00446 
00447     
00448     /**
00449      * operates on the given %parameter.
00450      * @param srcdest matrix with the source data.  The result
00451      *                 will be left here too.
00452      * @return true if apply successful or false otherwise.
00453      */
00454     virtual bool apply(matrix<T>& srcdest);
00455 
00456     /**
00457      * This computes a transformation matrix and transforms the given data.
00458      * @param src matrix with the source data. Each row represents a dataset.
00459      * @param dest matrix where the result will be left.
00460      * @return true if apply successful or false otherwise.
00461      */
00462     virtual bool apply(const matrix<T>& src,matrix<T>& dest);
00463 
00464 
00465     /** 
00466      * only computes the transformation matrix.
00467      * @param src matrix with the sourc data. Each row represents a dataset
00468      * @return true if apply successful or false otherwise.
00469      */
00470     bool computeTransformMatrix(const matrix<T>& src);
00471 
00472     /**
00473      * Returns the saved rotation matrix, which was computed with ICA.
00474      * @return a const reference to the last computed or used 
00475      * rotation matrix.
00476      */
00477     const matrix<T>& getRotationMatrix() const;
00478 
00479     /**
00480      * Returns the saved rotation matrix, which was computed with ICA.
00481      * @param dest last computed or used  rotation matrix will be stored here.
00482      */
00483     bool getRotationMatrix(matrix<T>& dest) const;
00484 
00485     /**
00486      * Returns the saved whitening matrix, which was computed with PCA
00487      * @return a const reference to the last computed or used 
00488      * whitening matrix.
00489      */
00490     const matrix<T>& getWhiteningMatrix() const;
00491 
00492     /**
00493      * Returns the saved whitening matrix, which was computed with ICA.
00494      * @param dest last computed or used  whitening matrix will be stored here.
00495      */
00496     bool getWhiteningMatrix(matrix<T>& dest) const;
00497 
00498     /**
00499      * Returns the saved transformation matrix.
00500      * This is only the product of (whitening matrix) * (rotation matrix).
00501      *
00502      * \b Note: If you want to use the transformation matrix to transform
00503      * datasets, you should subtract the offset vector from your data first.
00504      *
00505      * @return a const reference to the last computed or used 
00506      * transform matrix.
00507      */
00508     const matrix<T>& getTransformMatrix() const;
00509 
00510 
00511     /**
00512      * Returns the saved transformation matrix.
00513      * @param dest last computed or used transformation matrix will be stored
00514      *  here.
00515      */
00516     bool getTransformMatrix(matrix<T>& dest) const;
00517 
00518     /**
00519      * Returns the previously computed offset vector, which corresponds to the
00520      * mean of the data.
00521      *
00522      * @param result the offset vector will be written here.
00523      * @return true if the matrix could be computed, false otherwise.
00524      */
00525     bool getOffsetVector(vector<T>& result) const;
00526 
00527     /**
00528      * Returns the previously computed offset vector, which corresponds to the
00529      * mean of the data.
00530      *
00531      * @return a const reference to the last computed or used offset vector.
00532      */
00533     const vector<T>& getOffsetVector() const;
00534 
00535     /**
00536      * Transform an entire matrix according to a previosly computed transformation
00537      * matrix.
00538      * @param src the input data
00539      * @param dest here the transformed data will be left
00540      *
00541      * @return true if operation was succesfull and false otherwise
00542      */
00543     bool transform(const matrix<T>& src, matrix<T>& dest) const;  
00544 
00545     /**
00546      * Transform an entire matrix according to a previosly computed transformation
00547      * matrix.
00548      * @param srcdest the input data, the result will be left here, too
00549      *
00550      * @return true if operation was succesfull and false otherwise
00551      */
00552     bool transform(matrix<T>& srcdest) const;
00553 
00554 
00555     /**
00556      * Transforms a single vector according to a previously computed
00557      * transformation matrix.
00558      * @param src the data vector
00559      * @param dest the transformed vector will be left here
00560      */
00561     bool transform(const vector<T>& src, vector<T>& dest) const;
00562 
00563     /**
00564      * Transforms a single vector according to a previously computed
00565      * transformation matrix.
00566      * @param srcdest the input data, the result will be left here too
00567      * @return true if operation was succesfull and false otherwise
00568      */
00569     bool transform(vector<T>& srcdest) const;
00570 
00571     /**
00572      * Copy data of "other" functor.
00573      * @param other the functor to be copied
00574      * @return a reference to this functor object
00575      */
00576     fastICA& copy(const fastICA& other);
00577 
00578     /**
00579      * Alias for copy member
00580      * @param other the functor to be copied
00581      * @return a reference to this functor object
00582      */
00583     fastICA& operator=(const fastICA& other);
00584 
00585     /**
00586      * Returns a pointer to a clone of this functor.
00587      */
00588     virtual functor* clone() const;
00589 
00590     /**
00591      * Returns used parameters
00592      * @return const reference to the parameter object of this functor.
00593      */
00594     const parameters& getParameters() const;
00595 
00596 
00597     /**
00598      * Update functor's parameters.
00599      * This member updates the internal state of the functor according to the parameter set.
00600      * @return true if successful, false otherwise
00601      */
00602     virtual bool updateParameters();
00603 
00604  
00605   protected:
00606     /**
00607      * PCA functor which is applied before ICA with Whitening
00608      */
00609     principalComponents<T> pca;  
00610 
00611     /**
00612     * method to center the data
00613     */
00614     bool centerData(matrix<T>& srcdest) const;
00615 
00616     /**
00617      * ICA with deflationary approach
00618      */
00619     bool icaDeflationary(const matrix<T>& src, matrix<T>& dest, const parameters& par) const;
00620 
00621     /**
00622      * ICA with symmetric approach
00623      */
00624     bool icaSymmetric(const matrix<T>& src, matrix<T>& dest, const parameters& par) const;
00625 
00626 
00627     /**
00628      * method to determine if a vector is close enough to another
00629      */
00630     bool closeEnough(const vector<T>& a,
00631                      const vector<T>& b, 
00632                      const T epsilon) const;
00633 
00634     /**
00635      * method to determine if a vector is close enough to another
00636      */
00637     bool closeEnough(const matrix<T>& a,
00638                      const matrix<T>& b, 
00639                      const T epsilon) const;
00640 
00641     /**
00642      * Function pointer to the non-linearity function which should be used.
00643      * This pointer is set in updateParameters dependent on the
00644      * negentropyAproximation setting.
00645      *
00646      * Default: negentropyApproximation
00647      */
00648     T (fastICA<T>::*g) (const T x) const;
00649 
00650     /**
00651      * Function pointer to derivation of above g.
00652      */
00653     T (fastICA<T>::*gd) (const T x) const;
00654 
00655     /**
00656      * Constants for tuning negentropyApproximation functions are copied
00657      * from parameters in setParameters to this variable.
00658      */
00659     T a1;
00660 
00661     /**
00662      * Used to choose initial random vectors.
00663      */
00664     uniformDistribution uniDist;
00665 
00666     /**
00667      * First derivation of Exp negentropyApproximation.
00668      */
00669     T expo1(const T x) const;
00670 
00671     /**
00672      * Second derivation of Exp negentropyApproximation.
00673      */
00674     T expo2(const T x) const;
00675 
00676     /**
00677      * First derivation of Tanh negentropyApproximation.
00678      */
00679     T tanh1(const T x) const;
00680 
00681     /**
00682      * Second derivation of Tanh negentropyApproximation.
00683      */
00684     T tanh2(const T x) const;
00685 
00686     /**
00687      * First derivation of Pow4 negentropyApproximation (Kurtosis).
00688      */
00689     T kurt1(const T x) const;
00690 
00691     /**
00692      * Second derivation of Pow4 negentropyApproximation (Kurtosis).
00693      */
00694     T kurt2(const T x) const;
00695 
00696     /**
00697      * Matrix which is used to save the transform matrix.
00698      */
00699     matrix<T> transformMatrix;
00700 
00701     /**
00702      * Matrix which is used to save the whitening matrix.
00703      */
00704     matrix<T> whiteningMatrix;
00705 
00706     /**
00707      * Matrix which is used to save the whitening matrix.
00708      */
00709     matrix<T> rotationMatrix;
00710 
00711  };
00712 }
00713 
00714 #endif

Generated on Sat Apr 10 15:25:28 2010 for LTI-Lib by Doxygen 1.6.1