00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
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
00119
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
00219 AddTo(DotMultiplyOverwrite(&ex,
00220 Scale(-a2(), &U_squared)),
00221 &ex);
00222
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
00277 VectorToDiag(MapOverwrite(&Inv,
00278 0,
00279 AddTo(&Beta_vector, &sum_vector)),
00280 &D);
00281
00282
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
00431 AddTo(DotMultiplyOverwrite(&ex,
00432 Scale(-a2(), &u_squared)),
00433 &ex);
00434
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
00452 AddTo(DotMultiplyOverwrite(&ex,
00453 Scale(-a2(), &u_squared)),
00454 &ex);
00455
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
00563
00564
00565
00566
00567
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);
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
00675
00676
00677 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
00713
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
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
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
00881
00882
00883
00884
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
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);
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);
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
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;
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);
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
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
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 };
01409
01410 #endif