latest version v1.9 - last update 10 Apr 2010 |
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 .......: ltiKPCA.h 00027 * authors ....: Pablo Alvarado Jochen Wickel 00028 * organization: LTI, RWTH Aachen 00029 * creation ...: 27.11.2000 00030 * revisions ..: $Id: ltiKPCA.h,v 1.9 2006/02/08 12:28:10 ltilib Exp $ 00031 */ 00032 00033 #ifndef _LTI_K_P_C_A_H_ 00034 #define _LTI_K_P_C_A_H_ 00035 00036 #include "ltiPCA.h" 00037 #include "ltiEigenSystem.h" 00038 #include "ltiIoHandler.h" 00039 #include "ltiKernelFunctor.h" 00040 #include "ltiObjectFactory.h" 00041 00042 namespace lti { 00043 /** 00044 * Functor for computing a kernel principal component analysis. 00045 * 00046 * It receives a set of input vectors in form of a matrix (each row of 00047 * the matrix corresponds to an input vector), which will be transformed 00048 * with KPCA. 00049 * 00050 * The first time you use the apply()-method, the transformation 00051 * matrix will be computed. You can use this transformation matrix 00052 * with other data sets using the transform() methods. 00053 * 00054 * Please note that the eigenvector matrices will contain the 00055 * eigenvector in the COLUMNS and not in the rows, as could be 00056 * expected. This avoids the requirement of transposing matrices in 00057 * the vector transformations (see also lti::eigenSystem<T>). 00058 * 00059 * The Kernel PCA is described in Schoelkopf, B., Smola, A. and 00060 * Mueller, K. "Nonlinear Component Analysis as a Kernel Eigenvalue 00061 * Problem", Neural Computation, vol. 10, no. 5, pp. 1299-1319 00062 */ 00063 class kernelPCA: public linearAlgebraFunctor { 00064 public: 00065 /** 00066 * the parameters for the class principalComponents 00067 */ 00068 class parameters : public linearAlgebraFunctor::parameters { 00069 public: 00070 00071 /** 00072 * default constructor 00073 */ 00074 parameters(); 00075 00076 /** 00077 * copy constructor 00078 * @param other the parameters object to be copied 00079 */ 00080 parameters(const parameters& other); 00081 00082 /** 00083 * destructor 00084 */ 00085 ~parameters(); 00086 00087 /** 00088 * returns name of this type 00089 */ 00090 const char* getTypeName() const; 00091 00092 /** 00093 * copy the contents of a parameters object 00094 * @param other the parameters object to be copied 00095 * @return a reference to this parameters object 00096 */ 00097 parameters& copy(const parameters& other); 00098 00099 /** 00100 * Assigns the contents of the other object to this object 00101 */ 00102 inline parameters& operator=(const parameters& other); 00103 00104 /** 00105 * returns a pointer to a clone of the parameters 00106 */ 00107 virtual functor::parameters* clone() const; 00108 00109 /** 00110 * write the parameters in the given ioHandler 00111 * @param handler the ioHandler to be used 00112 * @param complete if true (the default) the enclosing begin/end will 00113 * be also written, otherwise only the data block will be written. 00114 * @return true if write was successful 00115 */ 00116 virtual bool write(ioHandler& handler,const bool complete=true) const; 00117 00118 /** 00119 * read the parameters from the given ioHandler 00120 * @param handler the ioHandler to be used 00121 * @param complete if true (the default) the enclosing begin/end will 00122 * be also written, otherwise only the data block will be written. 00123 * @return true if write was successful 00124 */ 00125 virtual bool read(ioHandler& handler,const bool complete=true); 00126 00127 # ifdef _LTI_MSC_6 00128 /** 00129 * this function is required by MSVC only, as a workaround for a 00130 * very awful bug, which exists since MSVC V.4.0, and still by 00131 * V.6.0 with all bugfixes (so called "service packs") remains 00132 * there... This method is also public due to another bug, so please 00133 * NEVER EVER call this method directly: use read() instead 00134 */ 00135 bool readMS(ioHandler& handler,const bool complete=true); 00136 00137 /** 00138 * this function is required by MSVC only, as a workaround for a 00139 * very awful bug, which exists since MSVC V.4.0, and still by 00140 * V.6.0 with all bugfixes (so called "service packs") remains 00141 * there... This method is also public due to another bug, so please 00142 * NEVER EVER call this method directly: use write() instead 00143 */ 00144 bool writeMS(ioHandler& handler,const bool complete=true) const; 00145 # endif 00146 00147 /** 00148 * Sets a new kernel function. A copy of the kernel will be 00149 * done (so it is useless to change the parameters of the given 00150 * kernel instance, because the internal kernel will never 00151 * notice the changes done to its "parent"). 00152 */ 00153 void setKernel(const kernelFunctor<double>& k); 00154 00155 /** 00156 * Sets a new kernel function. The kernel which is passed here as an 00157 * argument must have been allocated with new; it must not be 00158 * a local variable. On destruction of the parameters object, 00159 * the kernel will be deleted, i.e. this parameters instance will be 00160 * responsible for the memory managment of the object. 00161 */ 00162 void attachKernel(kernelFunctor<double>* k); 00163 00164 /** 00165 * Sets a new kernel function. The kernel which is passed here as an 00166 * argument is not deleted by the parameters object, the caller 00167 * must ensure that there are no memory leaks. 00168 */ 00169 void useExternalKernel(kernelFunctor<double>* k); 00170 00171 /** 00172 * create a new kernel function, using its class name. A pointer to the 00173 * kernel function is returned, so that the caller may modify 00174 * the kernel's parameters. 00175 */ 00176 kernelFunctor<double>* createKernel(const std::string& name) const; 00177 00178 // ------------------------------------------------ 00179 // the parameters 00180 // ------------------------------------------------ 00181 00182 /** 00183 * The kernel function. Try to use the kernel setting methods in order 00184 * to ensure a consistent memory managment of the pointed instance. 00185 * @see setKernel(),attachKernel(),useExternalKernel() 00186 * 00187 * Default value: "linearKernel" 00188 */ 00189 kernelFunctor<double>* kernel; 00190 00191 /** 00192 * This is the maximal dimension of the reduced vectors. 00193 * 00194 * Default value: 3 00195 */ 00196 int resultDim; 00197 00198 /** 00199 * This flag determines, if the functor should determine a 00200 * maximum allowable dimension itself. "Maximum dimension" means 00201 * that the dimension is equal to the number of eigenvalues of 00202 * the covariance matrix which are larger than zero. 00203 * 00204 * Default value: false 00205 */ 00206 bool autoDim; 00207 00208 /** 00209 * The eigensystem functor used for computing eigenvectors. 00210 * 00211 * Default value: lti::jacobi<double> 00212 */ 00213 eigenSystem<double> *eigen; 00214 00215 /** 00216 * This flag determines if the functor should perform a 00217 * whitening transform of the data. Whitening means that 00218 * 1. A KPCA is performed 00219 * 2. A scaling of the transformed data by the inverse of the 00220 * square root of the eigenvalues. 00221 * 00222 * The default is false. 00223 */ 00224 bool whitening; 00225 00226 00227 /** 00228 * The factor which determines relevant eigenvectors. An eigenvector 00229 * is considered relevant if its eigenvalue is at least as large 00230 * as the largest eigenvalue divided by this number. Usually, 00231 * it takes values between 1e4 and 1e6. 00232 */ 00233 double relevance; 00234 00235 private: 00236 /** 00237 * array of objects needed by the functor factory 00238 */ 00239 static const kernelFunctor<double>* kernelArray[]; 00240 00241 /** 00242 * kernel functor factory 00243 */ 00244 static objectFactory< kernelFunctor<double> > kfa; 00245 00246 /** 00247 * class name object used to detect the type name of an object instance. 00248 */ 00249 className cn; 00250 00251 /** 00252 * Flag used to inidicate if the local kernel functor must be deleted 00253 * by this object or not (just pointing to some external instance...) 00254 */ 00255 bool destroyKernel; 00256 00257 }; 00258 00259 /** 00260 * default constructor 00261 */ 00262 kernelPCA(); 00263 00264 /** 00265 * copy constructor 00266 * @param other the object to be copied 00267 */ 00268 kernelPCA(const kernelPCA& other); 00269 00270 /** 00271 * destructor 00272 */ 00273 virtual ~kernelPCA(); 00274 00275 /** 00276 * returns the name of this type ("kernelPCA") 00277 */ 00278 virtual const char* getTypeName() const; 00279 00280 /** 00281 * Computes the principal components of the data matrix 00282 * and transforms it according to the new coordinate system. 00283 * The result is the transformed matrix. 00284 * data and result must not be references to the same matrix. 00285 * This method uses the eigenvector functor given in the parameters. 00286 * By default, it uses ltilib's own jacobi functor. However, you can 00287 * speed it up considerably by using the eigensystem functor in 00288 * the lamath directory. 00289 * 00290 * If you don't need to transform the input data, and just want to 00291 * use the input matrix to compute the principal components you 00292 * can use the method computeTransformMatrix(). If you just need 00293 * to transform the data, without computing the transformation matrix, you 00294 * can use the method transform(). 00295 * 00296 * @param data dmatrix with the source data. 00297 * @param result dmatrix with the result data. 00298 * @return true if the KPCA could be computed, false otherwise 00299 */ 00300 virtual bool apply(const dmatrix& data, dmatrix& result); 00301 00302 /** 00303 * On-Place version of the transformation. 00304 * 00305 * If you don't need to transform the input data, and just want to 00306 * use the input matrix to compute the principal components you 00307 * can use the method computeTransformMatrix(). If you just need 00308 * to transform the data, without computing the transformation matrix, you 00309 * can use the method transform(). 00310 * 00311 * @param srcdest dmatrix with the source data, which will also contain 00312 * the result. 00313 * @return a reference to <code>srcdest</code>. 00314 */ 00315 virtual bool apply(dmatrix& srcdest); 00316 00317 /** 00318 * Transforms a single vector according to a previously computed 00319 * transformation matrix. (this is an alias for the transform() method) 00320 */ 00321 inline bool apply(const dvector &src, dvector& result) { 00322 return transform(src,result); 00323 } 00324 00325 /** 00326 * Transforms a single vector according to a previously computed 00327 * transformation matrix. 00328 * @param src the data vector 00329 * @param result the vector which will receive the transformed data 00330 * @return a reference to <code>result</code> 00331 */ 00332 virtual bool transform(const dvector &src, dvector& result) const; 00333 00334 /** 00335 * Transform an entire matrix according to a previously computed 00336 * transformation matrix. Unfortunately, we must choose a name 00337 * different from apply. 00338 * @param src the data matrix 00339 * @param result the matrix which will receive the transformed data 00340 * @return true if successful, false otherwise. 00341 */ 00342 virtual bool transform(const dmatrix &src, dmatrix& result) const; 00343 00344 /** 00345 * Transform an entire matrix according to a previously computed 00346 * transformation matrix. Unfortunately, we must choose a name 00347 * different from apply. 00348 * @param srcdest the data matrix. The result will be left here too. 00349 * @return true if successful, false otherwise. 00350 */ 00351 virtual bool transform(dmatrix &srcdest) const; 00352 00353 /** 00354 * Compute the transformation matrix. Similar to the apply() method, 00355 * but it does not transform the given data (this saves some time). 00356 * 00357 * @param src the matrix with the input data to be analysed. 00358 * @return true if transformation matrix could be computed, false otherwise 00359 */ 00360 virtual bool computeTransformMatrix(const dmatrix& src); 00361 00362 /** 00363 * Alias for computeTransformMatrix() 00364 */ 00365 virtual bool train(const dmatrix& src); 00366 00367 /** 00368 * Returns the previously computed eigenvalues of the covariance 00369 * matrix. 00370 * @param result the vector which will receive the eigenvalues. 00371 * @return true if the values could be obtained, false otherwise. 00372 */ 00373 virtual bool getEigenValues(dvector& result) const; 00374 00375 /** 00376 * Returns the previously computed eigenvalues of the covariance 00377 * matrix. 00378 * 00379 * @return a const reference to the last computed eigenvalues 00380 */ 00381 virtual const dvector& getEigenValues() const; 00382 00383 /** 00384 * Returns the previously computed eigenvectors of the covariance 00385 * matrix. Each ROW (as opposite to PCA) will contain the eigenvectors. 00386 * 00387 * @param result the matrix which will receive the eigenvectors. 00388 * Each row of the matrix contains one eigenvector. 00389 * @return true if the vectors could be obtained, false otherwise 00390 */ 00391 virtual bool getEigenVectors(dmatrix& result) const; 00392 00393 /** 00394 * Returns the previously computed eigenvectors of the covariance 00395 * matrix. 00396 * @return a const reference to the last computed eigenvectors. 00397 * Each row of the matrix contains one eigenvector. 00398 */ 00399 virtual const dmatrix& getEigenVectors() const; 00400 00401 /** 00402 * Set the dimension to which the vectors should be reduced. 00403 */ 00404 virtual void setDimension(int k); 00405 00406 /** 00407 * copy data of "other" functor. 00408 * @param other the functor to be copied 00409 * @return a reference to this functor object 00410 */ 00411 kernelPCA& copy(const kernelPCA& other); 00412 00413 /** 00414 * returns a pointer to a clone of this functor. 00415 */ 00416 virtual functor* clone() const; 00417 00418 /** 00419 * returns used parameters 00420 */ 00421 const parameters& getParameters() const; 00422 00423 /** 00424 * set functor's parameters. 00425 * This member makes a copy of <em>theParam</em>: the functor 00426 * will keep its own copy of the parameters! 00427 * @return true if successful, false otherwise 00428 */ 00429 virtual bool updateParameters(); 00430 00431 /** 00432 * Reads this functor from the given handler. 00433 */ 00434 virtual bool read(ioHandler &handler, const bool complete=true); 00435 00436 /** 00437 * Writes this functor to the given handler. 00438 */ 00439 virtual bool write(ioHandler &handler, const bool complete=true) const; 00440 00441 /** 00442 * Number of dimensions considered in the transformation 00443 * @return the number of dimensions used for the transformation. It 00444 * is always less or equal the number of dimensions of the input 00445 * vectors. 00446 */ 00447 int getUsedDimension() const { 00448 return usedDimensionality; 00449 } 00450 00451 protected: 00452 /** 00453 * Determines the intrinsic dimensionality of the data set if the 00454 * user specify autoDim, otherwise return parameters::resultDim. 00455 * The member usedDimensionality will be set with the returned value 00456 */ 00457 int checkDim(); 00458 00459 /** 00460 * compute kernel matrix. The data will be centered. 00461 */ 00462 bool computeKernelMatrix(const dmatrix& src,dmatrix& kmat); 00463 00464 /** 00465 * compute test kernel matrix. The data will be centered. 00466 * It will be assumed that the source data (srcData) contains the 00467 * right data 00468 */ 00469 bool computeTestKernelMatrix(const dmatrix& src,dmatrix& kmat) const; 00470 00471 /** 00472 * compute test kernel vector. The data will be centered. 00473 * It will be assumed that the source data (srcData) contains the 00474 * right data 00475 */ 00476 bool computeTestKernelVector(const dvector& src,dvector& kvct) const; 00477 00478 private: 00479 00480 /** 00481 * Kernel PCA requires the original data set 00482 */ 00483 dmatrix srcData; 00484 00485 /** 00486 * Mean of rows of srcData 00487 */ 00488 dvector Kunit; 00489 00490 /** 00491 * Mean of columns of srcData 00492 */ 00493 dvector unitK; 00494 00495 /** 00496 * Mean of all values in the srcData 00497 */ 00498 double unitKunit; 00499 00500 /** 00501 * ordered set of eigenvectors (sorted with decreasing order of 00502 * eigenvalues). 00503 */ 00504 dmatrix orderedEigVec; 00505 00506 /** 00507 * the transformation matrix will contain just a subset of 00508 * the orderedEigVec matrix. 00509 */ 00510 dmatrix transformMatrix; 00511 00512 /** 00513 * ordered eigenvalues (in decreasing order) 00514 */ 00515 dvector eigValues; 00516 00517 /** 00518 * scaling factors for the whitening transformation 00519 */ 00520 dvector whiteScale; 00521 00522 /** 00523 * dimensionality being used. 00524 */ 00525 int usedDimensionality; 00526 }; 00527 00528 bool read(ioHandler& handler, 00529 kernelPCA& kpca, 00530 const bool complete=true); 00531 00532 00533 bool write(ioHandler& handler, 00534 const kernelPCA& kpca, 00535 const bool complete=true); 00536 00537 } 00538 00539 #endif