/************************************************************************ * * * Program package T O O L D I A G * * * * Version 1.5 * * Date: Tue Feb 8 13:39:05 1994 * * * * NOTE: This program package is copyrighted in the sense that it * * may be used for scientific purposes. The package as a whole, or * * parts thereof, cannot be included or used in any commercial * * application without written permission granted by the author. * * No programs contained in this package may be copied for commercial * * distribution. * * * * All comments concerning this program package may be sent to the * * e-mail address 'tr@fct.unl.pt'. * * * ************************************************************************/ #include #include #include "def.h" #include "featslct.h" extern universe *U; extern bool verbose; extern float select_multivariate_minerr(); extern float select_multivariate_prob_dist(); extern float select_multivariate_InterClassDist(); static bool done; static str80 buf; /* Decides if the mutual distance between classes is calculated only between different classes or also within the same class */ bool mutual_all = TRUE; /*--------------------------------------------------------------*/ int num_euclid_distances = NUM_EUCLID_DISTANCES; struct euclid_distances { int index; char *name; } euclid_distance[] = { { J1, "Scatter matrices distance J1" }, { J2, "Scatter matrices distance J2" }, { J3, "Scatter matrices distance J3" }, { J4, "Scatter matrices distance J4" } }; int euclid_dist = EMPTY; /* default */ /*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/ #define MAX_MINKOWSKI (100.0) float minkowski_order; /* METRICS */ int num_distances = NUM_DISTANCES; struct distances { int index; char *name; } distance[] = { { MINKOWSKI, "Minkowski" }, { CITY_BLOCK, "City block" }, { EUCLIDEAN, "EUCLIDEAN DISTANCE" }, { CHEBYCHEV_DIST, "Chebychev" }, { NONLINEAR, "Nonlinear (Parzen & hyperspheric kernel)" } }; int dist = EUCLIDEAN; /* default */ /*--------------------------------------------------------------*/ bool return_log = FALSE; /* In order to obtain reasonable values */ float chernoff_parameter; /* SELECTION CRITERIA */ int num_criteria = NUM_CRITERIA; struct criteria { int index; char *name; int numDists; int dist[NUM_DISTANCES]; } criterion[] = { { MINERR, "Estimated minimal error probability", 0, {EMPTY} }, /* Multivariate normal distribution */ { CHERNOFF, "Chernoff", 0, {EMPTY} }, { BHATTACHARYYA, "Bhattacharyya distance", 0, {EMPTY} }, { BHATTACHARYYA_MATUSITA, "Matusita distance", 0, {EMPTY} }, { DIVERGENCE, "Divergence", 0, {EMPTY} }, { MAHALANOBIS, "Mahalanobis distance", 0, {EMPTY} }, { PATRICK_FISHER, "Patrick-Fisher", 0, {EMPTY} }, /* Non-parametric measures */ { INTER_CLASS_DISTANCE, "INTER-CLASS-DISTANCE", 5, {MINKOWSKI, CITY_BLOCK, EUCLIDEAN, CHEBYCHEV_DIST, NONLINEAR} }, { CHEBYCHEV, "Univariate Chebychev = 1 - (s1+s2)^2 / (m1-m2)^2" } }; int crit = MINERR; /* default */ /*--------------------------------------------------------------*/ /* SEARCH STRATEGIES */ int num_search_strategies = NUM_STRATEGIES; struct search_strategies { int index; char *name; int numCrits; /* ACTUALIZE WHEN ADDING NEW !!! */ int crit[NUM_CRITERIA]; } search_strategy[] = { { BF, "Best Features", 9, {MINERR, CHERNOFF, BHATTACHARYYA, BHATTACHARYYA_MATUSITA, DIVERGENCE, MAHALANOBIS, PATRICK_FISHER, INTER_CLASS_DISTANCE, CHEBYCHEV} }, { SFS, "Sequential Forward Search", 8, {MINERR, CHERNOFF, BHATTACHARYYA, BHATTACHARYYA_MATUSITA, DIVERGENCE, MAHALANOBIS, PATRICK_FISHER, INTER_CLASS_DISTANCE} }, { SBS, "Sequential Backward Search", 8, {MINERR, CHERNOFF, BHATTACHARYYA, BHATTACHARYYA_MATUSITA, DIVERGENCE, MAHALANOBIS, PATRICK_FISHER, INTER_CLASS_DISTANCE} }, { B_AND_B, "Branch and Bound", 7, {CHERNOFF, BHATTACHARYYA, BHATTACHARYYA_MATUSITA, DIVERGENCE, MAHALANOBIS, PATRICK_FISHER, INTER_CLASS_DISTANCE} } }; int strategy = BF; /* default */ /*--------------------------------------------------------------*/ static void getCriterion( strat, crit ) int strat, *crit; { int i, c; float f; char *critName = NULL; printf("\n ### Specify selection criterion for strategy %d = %s ###\n", strat+1, search_strategy[strat].name ); for( i = 0; i < search_strategy[strat].numCrits; i++ ) { c = search_strategy[strat].crit[i]; critName = criterion[ c ].name; printf("(%d) %s\n", i+1, critName ); } printf("Choice: "); get_d_range( &c, 1, search_strategy[strat].numCrits,LEFT_CLOSED__RIGHT_CLOSED); *crit = search_strategy[strat].crit[c-1]; if( *crit == CHERNOFF ) { printf(" Enter parameter of Chernoff probabilistic distance [0,1]: "); get_f_range( &f, 0.0, 1.0, LEFT_CLOSED__RIGHT_CLOSED ); chernoff_parameter = f; } if( *crit == MINERR ) initMINERR(); } void get_euclidean_dist() { int ed; printf("\n --- Specify Euclidan distance metric ---\n" ); for( ed = 0; ed < num_euclid_distances; ed++ ) { printf("(%d) %s\n", ed+1, euclid_distance[ ed ].name ); } printf("Choice: "); get_d_range( &ed, 1, num_euclid_distances, LEFT_CLOSED__RIGHT_CLOSED ); euclid_dist = ed - 1; } void getDistance( strat, crit, dist ) int strat, crit, *dist; { int d, i; float f; char *distName; euclid_dist = EMPTY; mutual_all = TRUE; printf("\n ### Specify distance metric for strategy %d = %s ###\n", strat+1, search_strategy[strat].name ); printf("\t\t and criterion = %s\n", criterion[crit].name ); for( i = 0; i < criterion[crit].numDists; i++ ) { d = criterion[crit].dist[i]; printf("(%d) %s\n", i+1, distance[ d ].name ); } printf("Choice: "); get_d_range( &d, 1, criterion[crit].numDists, LEFT_CLOSED__RIGHT_CLOSED ); *dist = criterion[crit].dist[d-1]; if( *dist == MINKOWSKI ) { printf(" Order of Minkowski metric: "); get_f_range( &f, 0.0, MAX_MINKOWSKI, LEFT_OPEN__RIGHT_CLOSED ); minkowski_order = f; } if( *dist == EUCLIDEAN ) { printf("Calculate Euclidean distance from scatter matrices\n"); printf("\ti.e. criteria J1 to J4? (y/n)n\b"); gets( buf ); if( buf[0] == 'y' ) get_euclidean_dist(); } if( *dist == NONLINEAR ) init_nonlinear_dist(); if( euclid_dist == EMPTY ) { printf("Calculate distance only between different classes (1)\n"); printf(" or also within the same class itself(2)?2\b"); gets(buf); if( buf[0] == '1' ) mutual_all = FALSE; } } static void selectFeatures( strat, crit ) int strat, crit; { switch( strat ) { case BF : selectFeaturesBF( crit ); break; case SFS : selectFeaturesSFS( crit ); break; case SBS : selectFeaturesSBS( crit ); break; case B_AND_B : selectFeaturesB_AND_B( crit ); break; } } static void featSelect( strat ) int strat; { getCriterion( strat, &crit ); if( criterion[crit].numDists > 0 ) getDistance( strat, crit, &dist ); printf("\n---------------------------------------------------------------\n"); printf("\tSelection strategy:\t%s\n\t criterion:\t%s", search_strategy[strat].name, criterion[crit].name ); if( crit == CHERNOFF ) { printf(" with s = %.3f", chernoff_parameter ); } if( criterion[crit].numDists > 0 ) { printf("\n\t distance metric:\t%s", distance[dist].name ); if( dist == MINKOWSKI ) printf(" of order s=%f", minkowski_order ); if( dist == EUCLIDEAN ) { if( euclid_dist != EMPTY ) { printf("\n\t based on criterion: %s\n", euclid_distance[ euclid_dist ].name ); } } if( mutual_all ) printf("\n\tCalculating mutual distance between ALL classes\n"); else printf("\n\tCalculating mutual distance only between DIFFERENT classes\n"); } printf("\n---------------------------------------------------------------\n"); printf("\tIs this what you want? (y/n)y\b"); gets(buf); if( buf[0] == 'n' ) return; selectFeatures( strat, crit ); save_selected_feat(); } void featSelectDEMO() { dist = EUCLIDEAN; euclid_dist = EMPTY; mutual_all = TRUE; printf("\n--- FEATURE SELECTION:\n\tSearch strategy = Sequential forward\n"); printf("\tSelection criterion = Euclidean distance\n"); printf("\t\tDistance is calculated between all classes.\n\n"); selectFeatures( SFS, INTER_CLASS_DISTANCE ); save_selected_feat(); } static void featSelectLoop() { int strat; printf("\n>>>>>----- FEATURE SELECTION MENU -----<<<<<<\n\n"); printf("----------- Search strategy ----------------\n"); for( strat = 0; strat < num_search_strategies; strat++ ) { printf("(%d) %s", strat+1, search_strategy[strat].name ); printf("\n"); } printf("\n(T)ools and old algorithms\n"); printf("(Q)uit\n\n"); printf("Choice: "); gets(buf); done = FALSE; switch( buf[0] ) { case '\0' : break; case 't': case 'T': featSelectToolsLoop(); break; case 'q': case 'Q': done = TRUE; break; default: sscanf( buf, "%d", &strat ); if( strat >= 1 && strat <= num_search_strategies ) { strategy = search_strategy[strat-1].index; featSelect( strategy ); } break; } close_nonlinear_dist(); } float selectMultivariate( crit, FSV, len ) int crit; FeatSelectVector FSV; int len; { float merit; switch( crit ) { case MINERR : merit = select_multivariate_minerr( FSV, len ); break; case CHERNOFF : case MAHALANOBIS : case BHATTACHARYYA : case BHATTACHARYYA_MATUSITA : case DIVERGENCE : case PATRICK_FISHER : merit = select_multivariate_prob_dist( crit, FSV, len ); break; case INTER_CLASS_DISTANCE : merit = select_multivariate_InterClassDist( crit, FSV, len ); break; default: fprintf(stderr,"What the hell is crit %d? - exit...\n", crit ); exit(1); } return( merit ); } void featSelectMain() { if( U->nrClass > 1 ) do { featSelectLoop(); } while( !done ); else { printf(" Please load universe first !..." ); gets( buf ); } }