fastica.h

Go to the documentation of this file.
00001 /* MLPACK 0.2
00002  *
00003  * Copyright (c) 2008, 2009 Alexander Gray,
00004  *                          Garry Boyer,
00005  *                          Ryan Riegel,
00006  *                          Nikolaos Vasiloglou,
00007  *                          Dongryeol Lee,
00008  *                          Chip Mappus, 
00009  *                          Nishant Mehta,
00010  *                          Hua Ouyang,
00011  *                          Parikshit Ram,
00012  *                          Long Tran,
00013  *                          Wee Chin Wong
00014  *
00015  * Copyright (c) 2008, 2009 Georgia Institute of Technology
00016  *
00017  * This program is free software; you can redistribute it and/or
00018  * modify it under the terms of the GNU General Public License as
00019  * published by the Free Software Foundation; either version 2 of the
00020  * License, or (at your option) any later version.
00021  *
00022  * This program is distributed in the hope that it will be useful, but
00023  * WITHOUT ANY WARRANTY; without even the implied warranty of
00024  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00025  * General Public License for more details.
00026  *
00027  * You should have received a copy of the GNU General Public License
00028  * along with this program; if not, write to the Free Software
00029  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00030  * 02110-1301, USA.
00031  */
00046 #ifndef FASTICA_H
00047 #define FASTICA_H
00048 
00049 #include "fastlib/fastlib.h"
00050 #include "lin_alg.h"
00051 
00052 #define LOGCOSH 0
00053 #define GAUSS 10
00054 #define KURTOSIS 20
00055 #define SKEW 30
00056 
00057 #define SYMMETRIC 0
00058 #define DEFLATION 1
00059 
00060 const fx_entry_doc fastica_entries[] = {
00061   {"seed", FX_PARAM, FX_INT, NULL,
00062    "  Seed for the random number generator.\n"},
00063   {"approach", FX_PARAM, FX_STR, NULL,
00064    "  Independent component recovery approach: 'deflation' or 'symmetric'.\n"},
00065   {"nonlinearity", FX_PARAM, FX_STR, NULL,
00066    "  Nonlinear function to use: 'logcosh', 'gauss', 'kurtosis', or 'skew'.\n"},
00067   {"fine_tune", FX_PARAM, FX_BOOL, NULL,
00068    "  Enable fine tuning.\n"},
00069   {"a1", FX_PARAM, FX_DOUBLE, NULL,
00070    "  Numeric constant for logcosh nonlinearity.\n"},
00071   {"a2", FX_PARAM, FX_DOUBLE, NULL,
00072    "  Numeric constant for gauss nonlinearity.\n"},
00073   {"mu", FX_PARAM, FX_DOUBLE, NULL,
00074    "  Numeric constant for fine-tuning Newton-Raphson method.\n"},
00075   {"stabilization", FX_PARAM, FX_BOOL, NULL,
00076    "  Use stabilization.\n"},
00077   {"epsilon", FX_PARAM, FX_DOUBLE, NULL,
00078    "  Threshold for convergence.\n"},
00079   {"max_num_iterations", FX_PARAM, FX_INT, NULL,
00080    "  Maximum number of iterations of fixed-point iterations.\n"},
00081   {"max_fine_tune", FX_PARAM, FX_INT, NULL,
00082    "  Maximum number of fine-tuning iterations.\n"},
00083   {"percent_cut", FX_PARAM, FX_DOUBLE, NULL,
00084    "  Number in [0,1] indicating percent data to use in stabilization updates.\n"},
00085   FX_ENTRY_DOC_DONE
00086 };
00087 
00088 const fx_module_doc fastica_doc = {
00089   fastica_entries, NULL,
00090   "Performs fastica.\n"
00091 };
00092 
00093 using namespace linalg__private;
00094 
00095 
00102 class FastICA {
00103   
00104  private:
00105 
00107   struct datanode* module_;
00108 
00110   Matrix X_;
00111 
00113   int approach_;
00114 
00116   int nonlinearity_;
00117 
00118   //const index_t first_eig;
00119   //const index_t last_eig;
00120 
00122   index_t num_of_IC_;
00123 
00125   bool fine_tune_;
00126 
00128   double a1_;
00129 
00131   double a2_;
00132 
00134   double mu_;
00135 
00137   bool stabilization_;
00138 
00140   double epsilon_;
00141 
00143   index_t max_num_iterations_;
00144 
00146   index_t max_fine_tune_;
00147 
00149   double percent_cut_;
00150 
00151 
00152 
00156   void SymmetricLogCoshUpdate_(index_t n, Matrix X, Matrix* B) {
00157     Matrix hyp_tan, col_vector, sum, temp1, temp2;
00158     
00159     MapOverwrite(&TanhArg,
00160                  a1(),
00161                  MulTransAInit(&X, B, &hyp_tan));
00162     
00163     
00164     ColVector(d, a1(), &col_vector);
00165     
00166     Scale(1 / (double) n,
00167           AddTo(MulInit(&X, &hyp_tan, &temp1),
00168                 DotMultiplyOverwrite(MulInit(&col_vector,
00169                                              MapOverwrite(&MinusArg,
00170                                                           n,
00171                                                           MatrixMapSum(&Square, 0, &hyp_tan, &sum)),
00172                                              &temp2),
00173                                      B)));
00174   }
00175 
00176 
00181   void SymmetricLogCoshFineTuningUpdate_(index_t n, Matrix X, Matrix* B) {
00182     Matrix Y, hyp_tan, Beta, Beta_Diag, D, sum, temp1, temp2, temp3;
00183         
00184     MulTransAInit(&X, B, &Y);
00185     MapInit(&TanhArg, a1(), &Y, &hyp_tan);
00186     DotMultiplySum(&Y, &hyp_tan, &Beta);
00187     VectorToDiag(MapOverwrite(&Inv,
00188                               0,
00189                               AddTo(&Beta,
00190                                     Scale(a1(),
00191                                           MapOverwrite(&MinusArg,
00192                                                        n,
00193                                                        MatrixMapSum(&Square, 0, &hyp_tan, &sum))))),
00194                  &D);
00195     
00196     AddExpert(mu(), 
00197               MulInit(MulInit(B,
00198                               SubFrom(VectorToDiag(&Beta, &Beta_Diag),
00199                                       MulTransAInit(&Y, &hyp_tan, &temp1)),
00200                               &temp2),
00201                       &D,
00202                       &temp3),
00203               B);
00204   }
00205 
00206 
00210   void SymmetricGaussUpdate_(index_t n, Matrix X, Matrix* B) {
00211     Matrix U, U_squared, ex, col_vector, sum, temp1, temp2;
00212     
00213     MulTransAInit(&X, B, &U);
00214     
00215     MapInit(&Square, 0, &U, &U_squared);
00216     MapInit(&ExpArg, -a2() / 2, &U_squared, &ex);
00217     DotMultiplyOverwrite(&ex, &U);
00218     //U is gauss
00219     AddTo(DotMultiplyOverwrite(&ex,
00220                                Scale(-a2(), &U_squared)),
00221           &ex);
00222     //ex is dGauss
00223     
00224     ColVector(d, a2(), &col_vector);
00225     
00226     Scale(1 / (double) n,
00227           SubOverwrite(MulInit(&X, &U, &temp1),
00228                        DotMultiplyOverwrite(B,
00229                                             MulInit(&col_vector,
00230                                                     Sum(&ex, &sum),
00231                                                     &temp2)),
00232                        B));
00233   }
00234 
00235 
00239   void SymmetricGaussFineTuningUpdate_(index_t n, Matrix X, Matrix* B) {
00240     Matrix Y, Y_squared_a2, ex, gauss, D, Beta, temp1, temp2, temp3;
00241     Vector Beta_vector, sum_vector;
00242         
00243     MulTransAInit(&X, B, &Y);
00244     MapInit(&SquareArg, a2(), &Y, &Y_squared_a2);
00245     MapInit(&ExpArg, -.5, &Y_squared_a2, &ex);
00246     DotMultiplyInit(&Y, &ex, &gauss);
00247         
00248     Beta_vector.Init(d);
00249     double *Y_col_j;
00250     double *gauss_col_j;
00251     for(index_t j = 0; j < d; j++) {
00252       Y_col_j = Y.GetColumnPtr(j);
00253       gauss_col_j = gauss.GetColumnPtr(j);
00254       double sum = 0;
00255       for(index_t i = 0; i < n; i++) {
00256         sum += Y_col_j[i] * gauss_col_j[i];
00257       }
00258       Beta_vector[j] = sum;
00259     }
00260 
00261         
00262     sum_vector.Init(d);
00263     double *Y_squared_a2_col_j;
00264     double *ex_col_j;
00265     for(index_t j = 0; j < d; j++) {
00266       Y_squared_a2_col_j = Y_squared_a2.GetColumnPtr(j);
00267       ex_col_j = ex.GetColumnPtr(j);
00268       double sum = 0;
00269       for(index_t i = 0; i < n; i++) {
00270         sum += (Y_squared_a2_col_j[i] - 1) * ex_col_j[i];
00271       }
00272       sum_vector[j] = sum;
00273     }
00274 
00275 
00276     //D = diag(1 ./ (Beta + sum((Y_squared_a2 - 1) .* ex)))
00277     VectorToDiag(MapOverwrite(&Inv,
00278                               0,
00279                               AddTo(&Beta_vector, &sum_vector)),
00280                  &D);
00281           
00282     //B = B + myy * B * (Y' * gauss - diag(Beta)) * D;
00283     AddExpert(mu(),
00284               MulInit(MulInit(B,
00285                               SubFrom(VectorToDiag(&Beta_vector, &Beta),
00286                                       MulTransAInit(&Y, &gauss, &temp1)),
00287                               &temp2),
00288                       &D,
00289                       &temp3),
00290               B);
00291   }
00292 
00293 
00297   void SymmetricKurtosisUpdate_(index_t n, Matrix X, Matrix* B) {
00298     Matrix temp1, temp2;
00299 
00300     Scale(1 / (double) n,
00301           MulInit(&X,
00302                   MapOverwrite(&pow,
00303                                3,
00304                                MulTransAInit(&X, B, &temp1)),
00305                   &temp2));
00306         
00307     AddTo(&temp2,
00308           Scale(-3, B));
00309   }
00310 
00311 
00315   void SymmetricKurtosisFineTuningUpdate_(index_t n, Matrix X, Matrix* B) {
00316     Matrix Y, G_pow_3, Beta, Beta_Diag, D_vector, D, temp1, temp2, temp3;
00317 
00318     MulTransAInit(&X, B, &Y);
00319     MapInit(&pow, 3, &Y, &G_pow_3);
00320 
00321     DotMultiplySum(&Y, &G_pow_3, &Beta);
00322 
00323     VectorToDiag(MapOverwrite(&Inv,
00324                               0,
00325                               MapInit(&Plus,
00326                                       -3 * n,
00327                                       &Beta,
00328                                       &D_vector)),
00329                  &D);
00330 
00331     AddExpert(mu(), 
00332               MulInit(MulInit(B,
00333                               SubFrom(VectorToDiag(&Beta, &Beta_Diag),
00334                                       MulTransAInit(&Y, &G_pow_3, &temp1)),
00335                               &temp2),
00336                       &D,
00337                       &temp3),
00338               B);
00339   }
00340 
00341 
00345   void SymmetricSkewUpdate_(index_t n, Matrix X, Matrix* B) {
00346     Matrix temp1;
00347 
00348     Scale(1 / (double) n,
00349           MulOverwrite(&X,
00350                        MapOverwrite(&Square,
00351                                     0,
00352                                     MulTransAInit(&X, B, &temp1)),
00353                        B));
00354 
00355   }
00356 
00357 
00361   void SymmetricSkewFineTuningUpdate_(index_t n, Matrix X, Matrix* B) {
00362     Matrix Y, G_skew, Beta, Beta_Diag, D_vector, D, temp1, temp2, temp3;
00363         
00364     MulTransAInit(&X, B, &Y);
00365     MapInit(&Square, 0, &Y, &G_skew);
00366     DotMultiplySum(&Y, &G_skew, &Beta);
00367     VectorToDiag(MapInit(&Inv, 0, &Beta, &D_vector),
00368                  &D);
00369         
00370     AddExpert(mu(), 
00371               MulInit(MulInit(B,
00372                               SubFrom(VectorToDiag(&Beta, &Beta_Diag),
00373                                       MulTransAInit(&Y, &G_skew, &temp1)),
00374                               &temp2),
00375                       &D,
00376                       &temp3),
00377               B);
00378   }
00379 
00380   
00384   void DeflationLogCoshUpdate_(index_t n, Matrix X, Vector* w) {
00385     Vector hyp_tan, temp1;
00386     
00387     MapOverwrite(&TanhArg,
00388                  a1(),
00389                  MulInit(w, &X, &hyp_tan));
00390         
00391     Scale(1 / (double) n,
00392           AddTo(MulInit(&X, &hyp_tan, &temp1),
00393                 Scale(a1() * (VectorMapSum(&Square, 0, &hyp_tan) - n),
00394                       w)));
00395   }
00396 
00397 
00401   void DeflationLogCoshFineTuningUpdate_(index_t n, Matrix X, Vector* w) {
00402     Vector hyp_tan, X_hyp_tan, Beta_w, temp1;
00403     
00404     MapOverwrite(&TanhArg,
00405                  a1(),
00406                  MulInit(w, &X, &hyp_tan));
00407     
00408     MulInit(&X, &hyp_tan, &X_hyp_tan);
00409     double Beta = la::Dot(X_hyp_tan, *w);
00410     
00411     AddExpert(mu(),
00412               Scale(1 / (a1() * (VectorMapSum(&Square, 0, &hyp_tan) - n) + Beta),
00413                     SubInit(&X_hyp_tan,
00414                             ScaleInit(Beta, w, &Beta_w),
00415                             &temp1)),
00416               w);
00417   }
00418 
00419 
00423   void DeflationGaussUpdate_(index_t n, Matrix X, Vector* w) {
00424     Vector u, u_squared, ex, temp1;
00425 
00426     MulInit(w, &X, &u);
00427     MapInit(&Square, 0, &u, &u_squared);
00428     MapInit(&ExpArg, -.5 * a2(), &u_squared, &ex);
00429     DotMultiplyOverwrite(&ex, &u);
00430     //u is gauss
00431     AddTo(DotMultiplyOverwrite(&ex,
00432                                Scale(-a2(), &u_squared)),
00433           &ex);
00434     //ex is dGauss
00435     Scale(1 / (double) n,
00436           AddTo(MulInit(&X, &u, &temp1),
00437                 Scale(-1 * Sum(&ex), w)));
00438   }
00439   
00440   
00444   void DeflationGaussFineTuningUpdate_(index_t n, Matrix X, Vector* w) {
00445     Vector u, u_squared, ex, X_gauss, Beta_w, temp1;
00446 
00447     MulInit(w, &X, &u);
00448     MapInit(&Square, 0, &u, &u_squared);
00449     MapInit(&ExpArg, -.5 * a2(), &u_squared, &ex);
00450     DotMultiplyOverwrite(&ex, &u);
00451     //u is gauss
00452     AddTo(DotMultiplyOverwrite(&ex,
00453                                Scale(-a2(), &u_squared)),
00454           &ex);
00455     //ex is dGauss
00456 
00457     MulInit(&X, &u, &X_gauss);
00458     double Beta = la::Dot(X_gauss, *w);
00459 
00460     AddExpert(mu(),
00461               Scale(1 / (Beta - Sum(&ex)),
00462                     SubInit(&X_gauss,
00463                             ScaleInit(Beta, w, &Beta_w),
00464                             &temp1)),
00465               w);
00466   }
00467 
00468   
00472   void DeflationKurtosisUpdate_(index_t n, Matrix X, Vector* w) {
00473     Vector temp1, temp2;
00474 
00475     Scale(1 / (double) n,
00476           MulInit(&X,
00477                   MapOverwrite(&pow,
00478                                3,
00479                                MulInit(w, &X, &temp1)),
00480                   &temp2));
00481             
00482     AddTo(&temp2,
00483           Scale(-3, w));
00484   }
00485   
00486   
00490   void DeflationKurtosisFineTuningUpdate_(index_t n, Matrix X, Vector* w) {
00491     Vector EXG_pow_3, Beta_w, temp1;
00492             
00493     Scale(1 / (double) n,
00494           MulInit(&X,
00495                   MapOverwrite(&pow,
00496                                3,
00497                                MulInit(w, &X, &temp1)),
00498                   &EXG_pow_3));
00499 
00500     double Beta = la::Dot(*w, EXG_pow_3);
00501             
00502     AddExpert(mu() / (Beta - 3),
00503               SubFrom(ScaleInit(Beta, w, &Beta_w),
00504                       &EXG_pow_3),
00505               w);
00506   }
00507 
00508   
00512   void DeflationSkewUpdate_(index_t n, Matrix X, Vector* w) {
00513     Vector temp1;
00514             
00515     Scale(1 / (double) n,
00516           MulInit(&X,
00517                   MapOverwrite(&Square,
00518                                0,
00519                                MulInit(w, &X, &temp1)),
00520                   w));
00521   }
00522 
00523   
00527   void DeflationSkewFineTuningUpdate_(index_t n, Matrix X, Vector* w) {
00528     Vector EXG_skew, Beta_w, temp1;
00529             
00530     Scale(1 / (double) n,
00531           MulInit(&X,
00532                   MapOverwrite(&Square,
00533                                0,
00534                                MulInit(w, &X, &temp1)),
00535                   &EXG_skew));
00536 
00537     double Beta = la::Dot(*w, EXG_skew);
00538             
00539     AddExpert(mu() / Beta,
00540               SubFrom(ScaleInit(Beta, w, &Beta_w),
00541                       &EXG_skew),
00542               w);
00543   }
00544   
00545     
00546   
00547  public:
00548 
00550   index_t d;
00552   index_t n;
00553 
00554   int approach() {
00555     return approach_;
00556   }
00557 
00558   int nonlinearity() {
00559     return nonlinearity_;
00560   }
00561 
00562   //  index_t first_eig() {
00563   //    return first_eig_;
00564   //  }
00565 
00566   //  index_t last_eig() {
00567   //    return last_eig_;
00568   //  }
00569 
00570   index_t num_of_IC() {
00571     return num_of_IC_;
00572   }
00573 
00574   bool fine_tune() {
00575     return fine_tune_;
00576   }
00577 
00578   double a1() {
00579     return a1_;
00580   }
00581 
00582   double a2() {
00583     return a2_;
00584   }
00585 
00586   double mu() {
00587     return mu_;
00588   }
00589 
00590   bool stabilization() {
00591     return stabilization_;
00592   }
00593 
00594   double epsilon() {
00595     return epsilon_;
00596   }
00597 
00598   index_t max_num_iterations() {
00599     return max_num_iterations_;
00600   }
00601 
00602   index_t max_fine_tune() {
00603     return max_fine_tune_;
00604   }
00605 
00606   double percent_cut() {
00607     return percent_cut_;
00608   }
00609 
00610   Matrix X() {
00611     return X_;
00612   }
00613 
00614 
00618   FastICA() {
00619   }
00620 
00624   int Init(Matrix X_in, struct datanode* module_in) {
00625 
00626     module_ = module_in;
00627 
00628     X_.Copy(X_in); // for some reason Alias makes this crash, so copy for now
00629     d = X_.n_rows();
00630     n = X_.n_cols();
00631 
00632     long seed = fx_param_int(module_, "seed", clock() + time(0));
00633     srand48(seed);
00634 
00635     
00636     const char* string_approach =
00637       fx_param_str(module_, "approach", "deflation");
00638     if(strcasecmp(string_approach, "deflation") == 0) {
00639       VERBOSE_ONLY( printf("using Deflation approach ") );
00640       approach_ = DEFLATION;
00641     }
00642     else if(strcasecmp(string_approach, "symmetric") == 0) {
00643       VERBOSE_ONLY( printf("using Symmetric approach ") );
00644       approach_ = SYMMETRIC;
00645     }
00646     else {
00647       printf("ERROR: approach must be 'deflation' or 'symmetric'\n");
00648       return SUCCESS_FAIL;
00649     }
00650     
00651     const char* string_nonlinearity =
00652       fx_param_str(module_, "nonlinearity", "logcosh");
00653     if(strcasecmp(string_nonlinearity, "logcosh") == 0) {
00654       VERBOSE_ONLY( printf("with log cosh nonlinearity\n") );
00655       nonlinearity_ = LOGCOSH;
00656     }
00657     else if(strcasecmp(string_nonlinearity, "gauss") == 0) {
00658       VERBOSE_ONLY( printf("with Gaussian nonlinearity\n") );
00659       nonlinearity_ = GAUSS;
00660     }
00661     else if(strcasecmp(string_nonlinearity, "kurtosis") == 0) {
00662       VERBOSE_ONLY( printf("with kurtosis nonlinearity\n") );
00663       nonlinearity_ = KURTOSIS;
00664     }
00665     else if(strcasecmp(string_nonlinearity, "skew") == 0) {
00666       VERBOSE_ONLY( printf("with skew nonlinearity\n") );
00667       nonlinearity_ = SKEW;
00668     }
00669     else {
00670       printf("\nERROR: nonlinearity not in {logcosh, gauss, kurtosis, skew}\n");
00671       return SUCCESS_FAIL;
00672     }
00673 
00674     //const index_t first_eig_ = fx_param_int(module_, "first_eig", 1);
00675     // for now, the last eig must be d, and num_of IC must be d, until I have time to incorporate PCA into this code
00676     //const index_t last_eig_ = fx_param_int(module_, "last_eig", d);
00677     num_of_IC_ = d; //fx_param_int(module_, "num_of_IC", d);
00678     fine_tune_ = fx_param_bool(module_, "fine_tune", false);
00679     a1_ = fx_param_double(module_, "a1", 1);
00680     a2_ = fx_param_double(module_, "a2", 1);
00681     mu_ = fx_param_double(module_, "mu", 1);
00682     stabilization_ = fx_param_bool(module_, "stabilization", false);
00683     epsilon_ = fx_param_double(module_, "epsilon", 0.0001);
00684   
00685     int int_max_num_iterations =
00686       fx_param_int(module_, "max_num_iterations", 1000);
00687     if(int_max_num_iterations < 0) {
00688       printf("ERROR: max_num_iterations = %d must be >= 0\n",
00689              int_max_num_iterations);
00690       return SUCCESS_FAIL;
00691     }
00692     max_num_iterations_ = (index_t) int_max_num_iterations;
00693 
00694     int int_max_fine_tune = fx_param_int(module_, "max_fine_tune", 5);
00695     if(int_max_fine_tune < 0) {
00696       printf("ERROR: max_fine_tune = %d must be >= 0\n",
00697              int_max_fine_tune);
00698       return SUCCESS_FAIL;
00699     }
00700     max_fine_tune_ = (index_t) int_max_fine_tune;
00701 
00702     percent_cut_ = fx_param_double(module_, "percent_cut", 1);
00703     if((percent_cut() < 0) || (percent_cut() > 1)) {
00704       printf("ERROR: percent_cut = %f must be an element in [0,1]\n",
00705              percent_cut());
00706       return SUCCESS_FAIL;
00707     }
00708     return SUCCESS_PASS;
00709   }
00710 
00711 
00712   // NOTE: these functions currently are public because some of them can
00713   //       serve as utilities that actually should be moved to lin_alg.h
00714 
00715 
00721   index_t GetSamples(int max, double percentage, Vector* selected_indices) {   
00722     
00723     index_t num_selected = 0;
00724     Vector rand_nums;
00725     rand_nums.Init(max);
00726     for(index_t i = 0; i < max; i++) {
00727       double rand_num = drand48();
00728       rand_nums[i] = rand_num;
00729       if(rand_num <= percentage) {
00730         num_selected++;
00731       }
00732     }
00733 
00734     selected_indices -> Init(num_selected);
00735     
00736     int j = 0;
00737     for(index_t i = 0; i < max; i++) {
00738       if(rand_nums[i] <= percentage) {
00739         (*selected_indices)[j] = i;
00740         j++;
00741       }
00742     }
00743 
00744     return num_selected;
00745   }
00746 
00747 
00753   index_t RandomSubMatrix(index_t n, double percent_cut, Matrix X, Matrix* X_sub) {
00754     Vector selected_indices;
00755     index_t num_selected = GetSamples(n, percent_cut, &selected_indices);
00756     MakeSubMatrixByColumns(selected_indices, X, X_sub);
00757     return num_selected;
00758   }
00759 
00760 
00764   int SymmetricFixedPointICA(bool stabilization_enabled,
00765                              bool fine_tuning_enabled,
00766                              double mu_orig, double mu_k, index_t failure_limit,
00767                              int used_nonlinearity, int g_fine, double stroke,
00768                              bool not_fine, bool taking_long,
00769                              int initial_state_mode,
00770                              Matrix X, Matrix* B, Matrix* W,
00771                              Matrix* whitening_matrix) {
00772     
00773     if(initial_state_mode == 0) {
00774       //generate random B
00775       B -> Init(d, num_of_IC());
00776       for(index_t i = 0; i < num_of_IC(); i++) {
00777         Vector b;
00778         B -> MakeColumnVector(i, &b);
00779         RandVector(b);
00780       }
00781     }
00782       
00783 
00784     Matrix B_old, B_old2;
00785 
00786     B_old.Init(d, num_of_IC());
00787     B_old2.Init(d, num_of_IC());
00788 
00789     B_old.SetZero();
00790     B_old2.SetZero();
00791 
00792 
00793     for(index_t round = 1; round <= (max_num_iterations() + 1); round++) {
00794       if(round == (max_num_iterations() + 1)) {
00795         printf("No convergence after %d steps\n", max_num_iterations());
00796         
00797         
00798         // orthogonalize B via: newB = B * (B' * B) ^ -.5;
00799         Matrix temp;
00800         temp.Copy(*B);
00801         Orthogonalize(temp, B);
00802 
00803         MulTransAOverwrite(B, whitening_matrix, W);
00804         return SUCCESS_PASS;
00805       }
00806         
00807       {
00808         Matrix temp;
00809         temp.Copy(*B);
00810         Orthogonalize(temp, B);
00811       }
00812 
00813       Matrix B_delta_cov;
00814       MulTransAInit(B, &B_old, &B_delta_cov);
00815       double min_abs_cos = DBL_MAX;
00816       for(index_t i = 0; i < d; i++) {
00817         double current_cos = fabs(B_delta_cov.get(i, i));
00818         if(current_cos < min_abs_cos) {
00819           min_abs_cos = current_cos;
00820         }
00821       }
00822       
00823       VERBOSE_ONLY( printf("delta = %f\n", 1 - min_abs_cos) );
00824 
00825       if(1 - min_abs_cos < epsilon()) {
00826         if(fine_tuning_enabled && not_fine) {
00827           not_fine = false;
00828           used_nonlinearity = g_fine;
00829           mu_ = mu_k * mu_orig;
00830           B_old.SetZero();
00831           B_old2.SetZero();
00832         }
00833         else {
00834           MulTransAOverwrite(B, whitening_matrix, W);
00835           return SUCCESS_PASS;
00836         }
00837       }
00838       else if(stabilization_enabled) {
00839 
00840         Matrix B_delta_cov2;
00841         MulTransAInit(B, &B_old2, &B_delta_cov2);
00842         double min_abs_cos2 = DBL_MAX;
00843         for(index_t i = 0; i < d; i++) {
00844           double current_cos2 = fabs(B_delta_cov2.get(i, i));
00845           if(current_cos2 < min_abs_cos2) {
00846             min_abs_cos2 = current_cos2;
00847           }
00848         }
00849 
00850         VERBOSE_ONLY( printf("stabilization delta = %f\n", 1 - min_abs_cos2) );
00851 
00852         if((stroke == 0) && (1 - min_abs_cos2 < epsilon())) {
00853           stroke = mu();
00854           mu_ *= .5;
00855           if((used_nonlinearity % 2) == 0) {
00856             used_nonlinearity += 1;
00857           }
00858         }
00859         else if(stroke > 0) {
00860           mu_ = stroke;
00861           stroke = 0;
00862 
00863           if((mu() == 1) && ((used_nonlinearity % 2) != 0)) {
00864             used_nonlinearity -= 1;
00865           }
00866         }
00867         else if((!taking_long) &&
00868                 (round > ((double) max_num_iterations() / 2))) {
00869           taking_long = true;
00870           mu_ *= .5;
00871           if((used_nonlinearity % 2) == 0) {
00872             used_nonlinearity += 1;
00873           }
00874         }
00875       }
00876 
00877       B_old2.CopyValues(B_old);
00878       B_old.CopyValues(*B);
00879 
00880       // show progress here, (the lack of code means no progress shown for now)
00881 
00882 
00883 
00884       // use Newton-Raphson method to update B
00885       switch(used_nonlinearity) {
00886           
00887       case LOGCOSH: {
00888         SymmetricLogCoshUpdate_(n, X, B);
00889         break;
00890       }
00891         
00892       case LOGCOSH + 1: {
00893         SymmetricLogCoshFineTuningUpdate_(n, X, B);
00894         break;  
00895       }
00896         
00897       case LOGCOSH + 2: {
00898         Matrix X_sub;
00899         index_t num_selected = RandomSubMatrix(n, percent_cut(), X, &X_sub);
00900         SymmetricLogCoshUpdate_(num_selected, X_sub, B);
00901         break;
00902       }
00903         
00904       case LOGCOSH + 3: {
00905         Matrix X_sub;
00906         index_t num_selected = RandomSubMatrix(n, percent_cut(), X, &X_sub);
00907         SymmetricLogCoshFineTuningUpdate_(num_selected, X_sub, B);
00908         break;
00909       }
00910 
00911       case GAUSS: {
00912         SymmetricGaussUpdate_(n, X, B);
00913         break;
00914       }
00915         
00916       case GAUSS + 1: {
00917         SymmetricGaussFineTuningUpdate_(n, X, B);
00918         break;
00919       }
00920 
00921       case GAUSS + 2: {
00922         Matrix X_sub;
00923         index_t num_selected = RandomSubMatrix(n, percent_cut(), X, &X_sub);
00924         SymmetricGaussUpdate_(num_selected, X_sub, B);
00925         break;
00926       }
00927 
00928       case GAUSS + 3: {
00929         Matrix X_sub;
00930         index_t num_selected = RandomSubMatrix(n, percent_cut(), X, &X_sub);
00931         SymmetricGaussFineTuningUpdate_(num_selected, X_sub, B);
00932         break;
00933       }
00934 
00935       case KURTOSIS: {
00936         SymmetricKurtosisUpdate_(n, X, B);
00937         break;
00938       }
00939         
00940       case KURTOSIS + 1: {
00941         SymmetricKurtosisFineTuningUpdate_(n, X, B);
00942         break;
00943       }
00944 
00945       case KURTOSIS + 2: {
00946         Matrix X_sub;
00947         index_t num_selected = RandomSubMatrix(n, percent_cut(), X, &X_sub);
00948         SymmetricKurtosisUpdate_(num_selected, X_sub, B);
00949         break;
00950       }
00951 
00952       case KURTOSIS + 3: {
00953         Matrix X_sub;
00954         index_t num_selected = RandomSubMatrix(n, percent_cut(), X, &X_sub);
00955         SymmetricKurtosisFineTuningUpdate_(num_selected, X_sub, B);
00956         break;
00957       }
00958 
00959       case SKEW: {
00960         SymmetricSkewUpdate_(n, X, B);
00961         break;
00962       }
00963         
00964       case SKEW + 1: {
00965         SymmetricSkewFineTuningUpdate_(n, X, B);
00966         break;
00967       }
00968 
00969       case SKEW + 2: {
00970         Matrix X_sub;
00971         index_t num_selected = RandomSubMatrix(n, percent_cut(), X, &X_sub);
00972         SymmetricSkewUpdate_(num_selected, X_sub, B);
00973         break;
00974       }
00975           
00976       case SKEW + 3: {
00977         Matrix X_sub;
00978         index_t num_selected = RandomSubMatrix(n, percent_cut(), X, &X_sub);
00979         SymmetricSkewFineTuningUpdate_(num_selected, X_sub, B);
00980         break;
00981       }
00982           
00983       default:
00984         printf("ERROR: invalid contrast function: used_nonlinearity = %d\n",
00985                used_nonlinearity);
00986         exit(SUCCESS_FAIL);
00987       }
00988     }
00989 
00990     // this code should be unreachable
00991     return SUCCESS_FAIL; 
00992   }
00993   
00994   
00998   int DeflationFixedPointICA(bool stabilization_enabled,
00999                              bool fine_tuning_enabled,
01000                              double mu_orig, double mu_k, index_t failure_limit,
01001                              int used_nonlinearity, int g_orig, int g_fine,
01002                              double stroke, bool not_fine, bool taking_long,
01003                              int initial_state_mode,
01004                              Matrix X, Matrix* B, Matrix* W,
01005                              Matrix* whitening_matrix) {
01006 
01007     B -> Init(d, d);
01008     B -> SetZero();
01009 
01010     index_t round = 0;
01011 
01012     index_t num_failures = 0;
01013 
01014     while(round < num_of_IC()) {
01015       VERBOSE_ONLY( printf("Estimating IC %d\n", round + 1) );
01016       mu_ = mu_orig;
01017       used_nonlinearity = g_orig;
01018       stroke = 0;
01019       not_fine = true;
01020       taking_long = false;
01021       int end_fine_tuning = 0;
01022         
01023       Vector w;
01024       if(initial_state_mode == 0) {
01025         w.Init(d);
01026         RandVector(w);
01027       }
01028 
01029       for(index_t i = 0; i < round; i++) {
01030         Vector b_i;
01031         B -> MakeColumnVector(i, &b_i);
01032         la::AddExpert(-la::Dot(b_i, w), b_i, &w);
01033       }
01034       la::Scale(1/sqrt(la::Dot(w, w)), &w); // normalize
01035 
01036       Vector w_old, w_old2;
01037       w_old.Init(d);
01038       w_old.SetZero();
01039       w_old2.Init(d);
01040       w_old2.SetZero();
01041 
01042       index_t i = 1;
01043       index_t gabba = 1;
01044       while(i <= max_num_iterations() + gabba) {
01045 
01046         for(index_t j = 0; j < round; j++) {
01047           Vector b_j;
01048           B -> MakeColumnVector(j, &b_j);
01049           la::AddExpert(-la::Dot(b_j, w), b_j, &w);
01050         }
01051         la::Scale(1/sqrt(la::Dot(w, w)), &w); // normalize
01052 
01053         if(not_fine) {
01054           if(i == (max_num_iterations() + 1)) {
01055             round++;
01056             num_failures++;
01057             if(num_failures > failure_limit) {
01058               printf("Too many failures to converge (%d). Giving up.\n", num_failures);
01059               return SUCCESS_FAIL;
01060             }
01061             break;
01062           }
01063         }
01064         else {
01065           if(i >= end_fine_tuning) {
01066             w_old.Copy(w);
01067           }
01068         }
01069 
01070         // check for convergence
01071         bool converged = false;
01072         Vector w_diff;
01073         la::SubInit(w_old, w, &w_diff);
01074 
01075         double delta1 = la::Dot(w_diff, w_diff);
01076         double delta2 = DBL_MAX;
01077           
01078         if(delta1 < epsilon()) {
01079           converged = true;
01080         }
01081         else {
01082           la::AddOverwrite(w_old, w, &w_diff);
01083 
01084           delta2 = la::Dot(w_diff, w_diff);
01085             
01086           if(delta2 < epsilon()) {
01087             converged = true;
01088           }
01089         }
01090 
01091         VERBOSE_ONLY( printf("delta = %f\n", min(delta1, delta2)) );
01092 
01093 
01094         if(converged) {
01095           if(fine_tuning_enabled & not_fine) {
01096             not_fine = false;
01097             gabba = max_fine_tune();
01098             w_old.SetZero();
01099             w_old2.SetZero();
01100             used_nonlinearity = g_fine;
01101             mu_ = mu_k * mu_orig;
01102 
01103             end_fine_tuning = max_fine_tune() + i;
01104           }
01105           else {
01106             num_failures = 0;
01107             Vector B_col_round, W_col_round;
01108 
01109             B -> MakeColumnVector(round, &B_col_round);
01110             W -> MakeColumnVector(round, &W_col_round);
01111 
01112             B_col_round.CopyValues(w);
01113             la::MulOverwrite(w, *whitening_matrix, &W_col_round);
01114 
01115             break; // this line is intended to take us to the next IC
01116           }
01117         }
01118         else if(stabilization_enabled) {
01119           converged = false;
01120           la::SubInit(w_old2, w, &w_diff);
01121             
01122           if(la::Dot(w_diff, w_diff) < epsilon()) {
01123             converged = true;
01124           }
01125           else {
01126             la::AddOverwrite(w_old2, w, &w_diff);
01127               
01128             if(la::Dot(w_diff, w_diff) < epsilon()) {
01129               converged = true;
01130             }
01131           }
01132             
01133           if((stroke == 0) && converged) {
01134             stroke = mu();
01135             mu_ *= .5;
01136             if((used_nonlinearity % 2) == 0) {
01137               used_nonlinearity++;
01138             }
01139           }
01140           else if(stroke != 0) {
01141             mu_ = stroke;
01142             stroke = 0;
01143             if((mu() == 1) && ((used_nonlinearity % 2) != 0)) {
01144               used_nonlinearity--;
01145             }
01146           }
01147           else if(not_fine && (!taking_long) &&
01148                   (i > ((double) max_num_iterations() / 2))) {
01149             taking_long = true;
01150             mu_ *= .5;
01151             if((used_nonlinearity % 2) == 0) {
01152               used_nonlinearity++;
01153             }
01154           }
01155         }
01156 
01157         w_old2.CopyValues(w_old);
01158         w_old.CopyValues(w);
01159           
01160         switch(used_nonlinearity) {
01161 
01162         case LOGCOSH: {
01163           DeflationLogCoshUpdate_(n, X, &w);
01164           break;
01165         }
01166 
01167         case LOGCOSH + 1: {
01168           DeflationLogCoshFineTuningUpdate_(n, X, &w);
01169           break;
01170         }
01171 
01172         case LOGCOSH + 2: {
01173           Matrix X_sub;
01174           index_t num_selected = RandomSubMatrix(n, percent_cut(), X, &X_sub);
01175           DeflationLogCoshUpdate_(num_selected, X_sub, &w);
01176           break;
01177         }
01178 
01179         case LOGCOSH + 3: {
01180           Matrix X_sub;
01181           index_t num_selected = RandomSubMatrix(n, percent_cut(), X, &X_sub);
01182           DeflationLogCoshFineTuningUpdate_(num_selected, X_sub, &w);
01183           break;
01184         }
01185 
01186         case GAUSS: {
01187           DeflationGaussUpdate_(n, X, &w);
01188           break;
01189         }
01190 
01191         case GAUSS + 1: {
01192           DeflationGaussFineTuningUpdate_(n, X, &w);
01193           break;
01194         }
01195 
01196         case GAUSS + 2: {
01197           Matrix X_sub;
01198           index_t num_selected = RandomSubMatrix(n, percent_cut(), X, &X_sub);
01199           DeflationGaussUpdate_(num_selected, X_sub, &w);
01200           break;
01201         }
01202 
01203         case GAUSS + 3: {
01204           Matrix X_sub;
01205           index_t num_selected = RandomSubMatrix(n, percent_cut(), X, &X_sub);
01206           DeflationGaussFineTuningUpdate_(num_selected, X_sub, &w);
01207           break;
01208         }
01209 
01210         case KURTOSIS: {
01211           DeflationKurtosisUpdate_(n, X, &w);
01212           break;
01213         }
01214 
01215         case KURTOSIS + 1: {
01216           DeflationKurtosisFineTuningUpdate_(n, X, &w);
01217           break;
01218         }
01219 
01220         case KURTOSIS + 2: {
01221           Matrix X_sub;
01222           index_t num_selected = RandomSubMatrix(n, percent_cut(), X, &X_sub);
01223           DeflationKurtosisUpdate_(num_selected, X_sub, &w);
01224           break;
01225         }
01226 
01227         case KURTOSIS + 3: {
01228           Matrix X_sub;
01229           index_t num_selected = RandomSubMatrix(n, percent_cut(), X, &X_sub);
01230           DeflationKurtosisFineTuningUpdate_(num_selected, X_sub, &w);
01231           break;
01232         }
01233 
01234         case SKEW: {
01235           DeflationSkewUpdate_(n, X, &w);
01236           break;
01237         }
01238 
01239         case SKEW + 1: {
01240           DeflationSkewFineTuningUpdate_(n, X, &w);
01241           break;
01242         }
01243 
01244         case SKEW + 2: {
01245           Matrix X_sub;
01246           index_t num_selected = RandomSubMatrix(n, percent_cut(), X, &X_sub);
01247           DeflationSkewUpdate_(num_selected, X_sub, &w);
01248           break;
01249         }
01250 
01251         case SKEW + 3: {
01252           Matrix X_sub;
01253           index_t num_selected = RandomSubMatrix(n, percent_cut(), X, &X_sub);
01254           DeflationSkewFineTuningUpdate_(num_selected, X_sub, &w);
01255           break;
01256         }
01257             
01258         default: 
01259           printf("ERROR: invalid contrast function: used_nonlinearity = %d\n",
01260                  used_nonlinearity);
01261           exit(SUCCESS_FAIL);
01262         }
01263         
01264         la::Scale(1/sqrt(la::Dot(w, w)), &w); // normalize
01265         i++;
01266       }
01267       round++;
01268     }
01269 
01270     return SUCCESS_PASS; 
01271   }
01272 
01273 
01280   int FixedPointICA(Matrix X, Matrix whitening_matrix, Matrix* W) {
01281     // ensure default values are passed into this function if the user doesn't care about certain parameters
01282 
01283     int g = nonlinearity();
01284     
01285     if(d < num_of_IC()) {
01286       printf("ERROR: must have num_of_IC <= Dimension!\n");
01287       W -> Init(0,0);
01288       return SUCCESS_FAIL;
01289     }
01290 
01291     W -> Init(d, num_of_IC());
01292 
01293     if((percent_cut() > 1) || (percent_cut() < 0)) {
01294       percent_cut_ = 1;
01295       printf("Setting percent_cut to 1\n");
01296     }
01297     else if(percent_cut() < 1) {
01298       if((percent_cut() * n) < 1000) {
01299         percent_cut_ = min(1000 / (double) n, (double) 1);
01300         printf("Warning: Setting percent_cut to %0.3f (%d samples).\n",
01301                percent_cut(),
01302                (int) floor(percent_cut() * n));
01303       }
01304     }
01305     
01306     int g_orig = g;
01307 
01308     if(percent_cut() != 1) {
01309       g_orig += 2;
01310     }
01311     
01312     if(mu() != 1) {
01313       g_orig += 1;
01314     }
01315 
01316     bool fine_tuning_enabled = true;
01317     int g_fine;
01318 
01319     if(fine_tune()) {
01320       g_fine = g + 1;
01321     }
01322     else {
01323       if(mu() != 1) {
01324         g_fine = g_orig;
01325       }
01326       else {
01327         g_fine = g_orig + 1;
01328       }
01329 
01330       fine_tuning_enabled = false;
01331     }
01332 
01333     bool stabilization_enabled;
01334     if(stabilization()) {
01335       stabilization_enabled = true;
01336     }
01337     else {
01338       if(mu() != 1) {
01339         stabilization_enabled = true;
01340       }
01341       else {
01342         stabilization_enabled = false;
01343       }
01344     }
01345 
01346     double mu_orig = mu();
01347     double mu_k = 0.01;
01348     index_t failure_limit = 5;
01349     int used_nonlinearity = g_orig;
01350     double stroke = 0;
01351     bool not_fine = true;
01352     bool taking_long = false;
01353 
01354     // currently we don't allow for guesses for the initial unmixing matrix B
01355     int initial_state_mode = 0;
01356 
01357     Matrix B;
01358 
01359     int ret_val = SUCCESS_FAIL;
01360     
01361     if(approach() == SYMMETRIC) {
01362       ret_val = 
01363         SymmetricFixedPointICA(stabilization_enabled, fine_tuning_enabled,
01364                                mu_orig, mu_k, failure_limit,
01365                                used_nonlinearity, g_fine, stroke,
01366                                not_fine, taking_long, initial_state_mode,
01367                                X, &B, W,
01368                                &whitening_matrix);
01369     }
01370     else if(approach() == DEFLATION) {
01371       ret_val = 
01372         DeflationFixedPointICA(stabilization_enabled, fine_tuning_enabled,
01373                                mu_orig, mu_k, failure_limit,
01374                                used_nonlinearity, g_orig, g_fine,
01375                                stroke, not_fine, taking_long, initial_state_mode,
01376                                X, &B, W,
01377                                &whitening_matrix);
01378     }
01379 
01380     return ret_val;
01381   }
01382 
01383 
01388   int DoFastICA(Matrix* W, Matrix* Y) {
01389 
01390     Matrix X_centered, X_whitened, whitening_matrix;
01391 
01392     Center(X(), &X_centered);
01393 
01394     WhitenUsingEig(X_centered, &X_whitened, &whitening_matrix);
01395   
01396     int ret_val =
01397       FixedPointICA(X_whitened, whitening_matrix, W);
01398 
01399     if(ret_val == SUCCESS_PASS) {
01400       la::MulInit(*W, X(), Y);
01401     }
01402     else {
01403       Y -> Init(0,0);
01404     }
01405 
01406     return ret_val;
01407   }
01408 }; /* class FastICA */
01409 
01410 #endif /* FASTICA_H */
Generated on Mon Jan 24 12:04:37 2011 for FASTlib by  doxygen 1.6.3