// pittnet.CPP // Backpropagation / ART1 / Kohonen / Radial Basis // The purpose of this prototype is to allow the user to construct and // initialize a series of neural nets. Using the concept of inheritance and // derived classes from C++ object oriented programming, the neceessity to // declare multiple large structures that duplicate attributes is eliminated // Utilizing pointers and the "new" function, dynamic arrays are established // The user can then specify the storage array size for the number of hidden // units and output units for the neural network while the program is running. // This strategy eliminates the need to establish extremely large arrays // while still maintaining the flexibility required to design nets of various. // shapes and sizes. The "Neural" classes allows the attributes of the newly // constructed networks to be stored for further processing. #include #include #include #include #include #include #include #include #include #include #define IA 16807 #define IM 2147483647 #define AM (1.0 / IM) #define IQ 127773 #define IR 2836 #define NTAB 32 #define NDIV (1+(IM-1) / NTAB) #define EPS 1.2e-7 #define RNMX (1.0 - EPS) // The following function is a random number generator float bedlam(long *idum); int gaset = -2500; float bedlam(long *idum) { int xj; long xk; static long iy=0; static long iv[NTAB]; float temp; if(*idum <= 0 || !iy) { if(-(*idum) < 1) { *idum = 1 + *idum; } else { *idum = -(*idum); } for(xj = NTAB+7; xj >= 0; xj--) { xk = (*idum) / IQ; *idum = IA * (*idum - xk * IQ) - IR * xk; if(*idum < 0) { *idum += IM; } if(xj < NTAB) { iv[xj] = *idum; } } iy = iv[0]; } xk = (*idum) / IQ; *idum = IA * (*idum - xk * IQ) - IR * xk; if(*idum < 0) { *idum += IM; } xj = iy / NDIV; iy = iv[xj]; iv[xj] = *idum; if((temp=AM*iy) > RNMX) { return(RNMX); } else { return(temp); } } // end of bedlam function //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // (Fully connected network using backpropagation) // In this base class, all nodes in the network have the following attributes class Processing_units { public: float *processing_unit_input; int number_of_input_units; void establish_array_of_processing_unit_inputs(void); float *weight_of_inputs; void establish_weight_vector_for_processing_units(void); float bias; float output_signal; void calculate_output_signal(int activation_function); float calculate_output_signal_derivative(int afun); float error_information_term; void calculate_weight_and_bias_correction_terms(float learning_rate); float *weight_correction_term; float bias_correction_term; float sum_of_weighted_inputs; void update_weights_and_biases(void); Processing_units(); ~Processing_units(); }; Processing_units::Processing_units() { bias = 0.0; output_signal = 0.0; error_information_term = 0.0; bias_correction_term = 0.0; sum_of_weighted_inputs = 0.0; } Processing_units::~Processing_units() { delete [] processing_unit_input; delete [] weight_of_inputs; delete [] weight_correction_term; } // Define base class member functions void Processing_units::establish_array_of_processing_unit_inputs(void) { processing_unit_input = new float[number_of_input_units]; weight_of_inputs = new float[number_of_input_units]; weight_correction_term = new float[number_of_input_units]; } void Processing_units::establish_weight_vector_for_processing_units(void) { for(int i = 0; i < number_of_input_units; i++) { // weights range from 1 to -1 weight_of_inputs[i] = 1.0 - (2.0 * bedlam((long*)(gaset))); } } void Processing_units::calculate_output_signal(int activation_function) { sum_of_weighted_inputs = 0.0; for(int i = 0; i < number_of_input_units; i++) { if(i == number_of_input_units - 1) {sum_of_weighted_inputs += (processing_unit_input[i] * weight_of_inputs[i]) + bias;} else {sum_of_weighted_inputs += processing_unit_input[i] * weight_of_inputs[i];} } switch(activation_function) { case 1: // binary sigmoid function output_signal = 1.0 / (1.0 + exp(-1.0 * sum_of_weighted_inputs)); break; case 2: // bipolar sigmoid function output_signal = (2.0 / (1.0 + exp(-1.0 * sum_of_weighted_inputs))) - 1; break; } } float Processing_units::calculate_output_signal_derivative(int afun) { float derivative; switch(afun) // derivative used based on activation function seleted { case 1: // binary sigmoid function derivative = output_signal * (1.0 - output_signal); break; case 2: // bipolar sigmoid function derivative = 0.5 * (1.0 + output_signal) * (1.0 - output_signal); break; } return derivative; } void Processing_units::calculate_weight_and_bias_correction_terms(float learning_rate) { for(int i = 0; i < number_of_input_units; i++) {weight_correction_term[i] = learning_rate * error_information_term * processing_unit_input[i];} bias_correction_term = learning_rate * error_information_term; error_information_term = 0.0; update_weights_and_biases(); } void Processing_units::update_weights_and_biases(void) { for(int i = 0; i < number_of_input_units; i++) {weight_of_inputs[i] = weight_of_inputs[i] + weight_correction_term[i];} bias = bias + bias_correction_term; } // Declare a derived class "Hidden_units" for hidden layer of network class Hidden_units : public Processing_units { public: void calculate_hidden_error_information_term(int afun); }; // Define member functions for derived class "Hidden_units" void Hidden_units::calculate_hidden_error_information_term(int afun) { float af = afun; float output_signal_derivative = calculate_output_signal_derivative(af); error_information_term = error_information_term * output_signal_derivative; } // Declare a derived class "Output_units" for output layer of network class Output_units : public Processing_units { public: void calculate_output_error_information_term(float target_value, int af); float absolute_error_difference; float error_difference_squared; }; // Define member functions for derived class "Output_units" void Output_units::calculate_output_error_information_term(float target_value, int af) { float afun = af; float output_signal_derivative = calculate_output_signal_derivative(afun); absolute_error_difference = fabs(target_value - output_signal); error_information_term = (target_value - output_signal) * output_signal_derivative; error_difference_squared = pow((target_value - output_signal), 2.0); } // Create classes to contain neural net specifications class Hidden_layer { public: Hidden_units *node_in_hidden_layer; int nodes_in_hidden_layer; ~Hidden_layer(); }; Hidden_layer::~Hidden_layer() {delete [] node_in_hidden_layer;} // The following class represents an artificial neural network containing // the topology, weights, training performance and testing performance class Back_Topology { public: Hidden_layer *hidden_layer_number; Output_units *node_in_output_layer; int number_of_hidden_layers; int activation_function_for_hidden_layer; int nodes_in_output_layer; int activation_function_for_output_layer; int signal_dimensions; int number_of_tests; void establish_activation_functions(void); void construct_and_initialize_backprop_network(void); void upload_network(void); void savenet(void); ~Back_Topology(); }; void Back_Topology::construct_and_initialize_backprop_network(void) { int nodes, inputs_to_output_node; char netcreate; int looploc = 0; do { cout <<"\n"; cout << "Do you wish to" << "\n\n"; cout << "C. Create your own Backprop Network " << "\n"; cout << "U. Upload an existing Backprop Network " << "\n\n"; cout << "Your choice?: "; cin >> netcreate; netcreate = toupper(netcreate); cout << "\n"; if((netcreate == 'C') || (netcreate == 'U')) {looploc = 1;} } while(looploc <= 0); if(netcreate == 'U') {upload_network();} else { cout << "Please enter the dimensions of the input vector: "; cin >> signal_dimensions; cout << "\n\n"; do { cout << "please enter the number of hidden layers (0 - 2): "; cin >> number_of_hidden_layers; cout << "\n\n"; } while(number_of_hidden_layers > 2); if(number_of_hidden_layers > 0) { hidden_layer_number = new Hidden_layer[number_of_hidden_layers]; for(int layer = 0; layer < number_of_hidden_layers; layer++) { cout << "please enter the number of nodes in hidden layer " << layer + 1 << ": "; cin >> hidden_layer_number[layer].nodes_in_hidden_layer; cout << "\n\n"; } } cout << "\n"; cout << "please enter the number of nodes in the output layer: "; cin >> nodes_in_output_layer; cout << "\n\n"; // establish for dynamic arrays for number of nodes in hidden and output layers if(number_of_hidden_layers > 0) { for(int layer = 0; layer < number_of_hidden_layers; layer++) { nodes = hidden_layer_number[layer].nodes_in_hidden_layer; hidden_layer_number[layer].node_in_hidden_layer = new Hidden_units[nodes]; } } node_in_output_layer = new Output_units[nodes_in_output_layer]; if(number_of_hidden_layers > 0) { // establish input connection between signal and hidden layer for(nodes = 0; nodes < hidden_layer_number[0].nodes_in_hidden_layer; nodes++) { hidden_layer_number[0].node_in_hidden_layer[nodes].number_of_input_units = signal_dimensions; hidden_layer_number[0].node_in_hidden_layer[nodes].establish_array_of_processing_unit_inputs(); hidden_layer_number[0].node_in_hidden_layer[nodes].establish_weight_vector_for_processing_units(); hidden_layer_number[0].node_in_hidden_layer[nodes].bias = 1.0 - (2.0 * bedlam((long*)(gaset))); } if(number_of_hidden_layers > 1) { // establish connection between first and second hidden layers for(nodes = 0; nodes < hidden_layer_number[1].nodes_in_hidden_layer; nodes++) { hidden_layer_number[1].node_in_hidden_layer[nodes].number_of_input_units = hidden_layer_number[0].nodes_in_hidden_layer; hidden_layer_number[1].node_in_hidden_layer[nodes].establish_array_of_processing_unit_inputs(); hidden_layer_number[1].node_in_hidden_layer[nodes].establish_weight_vector_for_processing_units(); hidden_layer_number[1].node_in_hidden_layer[nodes].bias = 1.0 - (2.0 * bedlam((long*)(gaset))); } } } // determine number of inputs to the output layer if(number_of_hidden_layers > 0) {inputs_to_output_node = hidden_layer_number[number_of_hidden_layers - 1].nodes_in_hidden_layer;} else {inputs_to_output_node = signal_dimensions;} // establish input connections to output layer for(nodes = 0; nodes < nodes_in_output_layer; nodes++) { node_in_output_layer[nodes].number_of_input_units = inputs_to_output_node; node_in_output_layer[nodes].establish_array_of_processing_unit_inputs(); node_in_output_layer[nodes].establish_weight_vector_for_processing_units(); node_in_output_layer[nodes].bias = 1.0 - (2.0 * bedlam((long*)(gaset))); } establish_activation_functions(); // for hidden and output nodes } } // end construct and initialize neural network function void Back_Topology::upload_network(void) { char getname[13]; ifstream get_ptr; int netid, nodes, dim, inputs_to_output_node, hid, inputs; int dolock = 0; do { cout << "\n\n"; cout << "Please enter the name of the file which holds the Backpropagation network" << "\n"; cin >> getname; cout << "\n"; get_ptr.open(getname, ios::in); get_ptr >> netid; if(netid == 1) {dolock = 1;} else { cout << "Error** file contents do not match Backprop specifications" << "\n"; cout << "try again" << "\n"; get_ptr.close(); } } while(dolock <= 0); get_ptr >> signal_dimensions; get_ptr >> activation_function_for_output_layer; get_ptr >> nodes_in_output_layer; get_ptr >> inputs_to_output_node; // establish output layer node_in_output_layer = new Output_units[nodes_in_output_layer]; for(nodes = 0; nodes < nodes_in_output_layer; nodes++) { node_in_output_layer[nodes].number_of_input_units = inputs_to_output_node; node_in_output_layer[nodes].establish_array_of_processing_unit_inputs(); node_in_output_layer[nodes].establish_weight_vector_for_processing_units(); get_ptr >> node_in_output_layer[nodes].bias; } for(nodes = 0; nodes < nodes_in_output_layer; nodes++) { for(dim = 0; dim < inputs_to_output_node; dim++) {get_ptr >> node_in_output_layer[nodes].weight_of_inputs[dim];} } // establish hidden layer(s) get_ptr >> number_of_hidden_layers; if(number_of_hidden_layers > 0) { hidden_layer_number = new Hidden_layer[number_of_hidden_layers]; get_ptr >> activation_function_for_hidden_layer; for(hid = 0; hid < number_of_hidden_layers; hid++) { get_ptr >> hidden_layer_number[hid].nodes_in_hidden_layer; nodes = hidden_layer_number[hid].nodes_in_hidden_layer; hidden_layer_number[hid].node_in_hidden_layer = new Hidden_units[nodes]; if(hid == 0) {inputs = signal_dimensions;} else {inputs = hidden_layer_number[0].nodes_in_hidden_layer;} for(nodes = 0; nodes < hidden_layer_number[hid].nodes_in_hidden_layer; nodes++) { hidden_layer_number[hid].node_in_hidden_layer[nodes].number_of_input_units = inputs; hidden_layer_number[hid].node_in_hidden_layer[nodes].establish_array_of_processing_unit_inputs(); get_ptr >> hidden_layer_number[hid].node_in_hidden_layer[nodes].bias; } for(nodes = 0; nodes < hidden_layer_number[hid].nodes_in_hidden_layer; nodes++) { for(dim = 0; dim < inputs; dim++) {get_ptr >> hidden_layer_number[hid].node_in_hidden_layer[nodes].weight_of_inputs[dim];} } } } get_ptr.close(); } void Back_Topology::savenet(void) { char savename[13]; ofstream save_ptr; int nodes, dim, inputs, hid; cout << "\n\n"; cout << "Please enter the name of the file that will hold" << "\n"; cout << "the Backpropagation network: "; cin >> savename; save_ptr.open(savename, ios::out); save_ptr << 1 << "\n"; // network identifier number save_ptr << signal_dimensions << "\n"; save_ptr << activation_function_for_output_layer << "\n"; save_ptr << nodes_in_output_layer << "\n"; if(number_of_hidden_layers > 0) {inputs = hidden_layer_number[number_of_hidden_layers - 1].nodes_in_hidden_layer;} else {inputs = signal_dimensions;} save_ptr << inputs << "\n"; for(nodes = 0; nodes < nodes_in_output_layer; nodes++) {save_ptr << node_in_output_layer[nodes].bias << " ";} save_ptr << "\n"; for(nodes = 0; nodes < nodes_in_output_layer; nodes++) { for(dim = 0; dim < inputs; dim++) {save_ptr << node_in_output_layer[nodes].weight_of_inputs[dim] << " ";} save_ptr << "\n"; } save_ptr << number_of_hidden_layers << "\n"; if(number_of_hidden_layers > 0) { save_ptr << activation_function_for_hidden_layer << "\n"; for(hid = 0; hid < number_of_hidden_layers; hid++) { save_ptr << hidden_layer_number[hid].nodes_in_hidden_layer << "\n"; if(hid == 0) {inputs = signal_dimensions;} else {inputs = hidden_layer_number[0].nodes_in_hidden_layer;} for(nodes = 0; nodes < hidden_layer_number[hid].nodes_in_hidden_layer; nodes++) {save_ptr << hidden_layer_number[hid].node_in_hidden_layer[nodes].bias << " ";} save_ptr << "\n"; for(nodes = 0; nodes < hidden_layer_number[hid].nodes_in_hidden_layer; nodes++) { for(dim = 0; dim < inputs; dim++) {save_ptr << hidden_layer_number[hid].node_in_hidden_layer[nodes].weight_of_inputs[dim] << " ";} save_ptr << "\n"; } } } save_ptr.close(); } Back_Topology::~Back_Topology() { delete [] hidden_layer_number; delete [] node_in_output_layer; } void Back_Topology::establish_activation_functions(void) { int bchoice, count; int dolock = 1; for(count = 0; count < 2; count++) { cout << "\n"; if((count == 0) && (number_of_hidden_layers > 0)) {cout << "For the nodes in the hidden layer(s):" << "\n";} else {cout << "For the output layer:" << "\n";} do { cout << "please select the type of activation function you wish the nodes to use" << "\n\n"; cout << "1. Binary Sigmoid Function " << "\n"; cout << "2. Bipolar Sigmoid Function " << "\n\n"; cout << "Your Selection "; cin >> bchoice; cout << "\n\n"; if((bchoice == 1) || (bchoice == 2)) {dolock = 0;} } while(dolock >= 1); if((count == 0) && (number_of_hidden_layers > 0)) {activation_function_for_hidden_layer = bchoice;} else {activation_function_for_output_layer = bchoice;} } } // Declare classes that will establish training and testing data arrays class sample_data { public: float *data_in_sample; // pointer to the dimensions of a single signal ~sample_data(); }; sample_data:: ~sample_data() {delete [] data_in_sample;} class Data_type { public: char filename[13]; // File containing data for network training or testing char resultsname[13]; // File containing data for results of training or testing int signal_dimensions; // Number of dimensions contained in signal int sample_number; // Number of signals in training set int nodes_in_output_layer; // Dimensions of test data output sample_data *number_of_samples; // Pointer to the array containing signals float *max_output_value; float *min_output_value; virtual void determine_sample_number(void); void specify_signal_sample_size(void); virtual void load_data_into_array(void); // Function to place data into the array void acquire_net_info(int signal, int no_output_nodes); void delete_signal_array(void); // Function to free memory allocated to hold signals virtual void normalize_data_in_array(void); ~Data_type(); // class destructor }; Data_type::~Data_type() { delete [] max_output_value; delete [] min_output_value; } // define functions of Data_type Class void Data_type :: determine_sample_number(void) { ifstream dfile_ptr; // pointer to a file dfile_ptr.open(filename, ios::in); float hold; int lock = 1; sample_number = 0; do { if(dfile_ptr.eof()){lock = 0;} else {dfile_ptr >> hold; sample_number += 1;} }while(lock > 0); dfile_ptr.close(); sample_number = int(sample_number / (signal_dimensions + nodes_in_output_layer)); } void Data_type::specify_signal_sample_size(void) { char tchoice; int dolock = 1; do { cout <<"\n"; cout << "Please select the number of samples you wish to use" << "\n\n"; cout << " A. All samples in the file" << "\n"; cout << " S. Specific number of samples"<< "\n\n"; cout << " Your Selection: "; cin >> tchoice; cout << "\n\n"; tchoice = toupper(tchoice); if((tchoice == 'A') || (tchoice == 'S')) {dolock = 0;} } while(dolock >= 1); cout <<"\n"; if(tchoice == 'A') {determine_sample_number();} else { cout << "\n"; cout << "please enter the number of testing samples you wish to use: "; cin >> sample_number; cout << "\n"; } load_data_into_array(); } void Data_type::normalize_data_in_array(void) { int imax, imin, trigger; float min, max, rmax, rmin; int total_dimension = signal_dimensions + nodes_in_output_layer; int i, j; max_output_value = new float[nodes_in_output_layer]; min_output_value = new float[nodes_in_output_layer]; for(j = 0; j < total_dimension; j++) { trigger = 1; // identify the minimum and maximum values for each dimension for(i = 0; i < sample_number; i++) { if(i == 0) { max = number_of_samples[i].data_in_sample[j]; min = number_of_samples[i].data_in_sample[j]; if((j >= (total_dimension - nodes_in_output_layer))) { min_output_value[j - (total_dimension - nodes_in_output_layer)] = min; max_output_value[j - (total_dimension - nodes_in_output_layer)] = max; } } else { if(number_of_samples[i].data_in_sample[j] < min) { min = number_of_samples[i].data_in_sample[j]; if(j >= (total_dimension - nodes_in_output_layer)) {min_output_value[j - (total_dimension - nodes_in_output_layer)] = min;} } if(number_of_samples[i].data_in_sample[j] > max) { max = number_of_samples[i].data_in_sample[j]; if(j >= (total_dimension - nodes_in_output_layer)) {max_output_value[j - (total_dimension - nodes_in_output_layer)] = max;} } } } imax = int(max_output_value[j - (total_dimension - nodes_in_output_layer)]); imin = int(min_output_value[j - (total_dimension - nodes_in_output_layer)]); rmax = max_output_value[j - (total_dimension - nodes_in_output_layer)]; rmin = min_output_value[j - (total_dimension - nodes_in_output_layer)]; if((imax == 1) && (imin == 0) && (rmax <= 1.0) && (rmin <= 0.0)) {trigger = 0;} if((imax == 1) && (imin == 1) && (rmax <= 1.0) && (rmin <= 1.0)) {trigger = 0;} if((imax == 0) && (imin == 0) && (rmax <= 0.0) && (rmin <= 0.0)) {trigger = 0;} // normalize the values in each dimension of the signal if(trigger != 0) { for(i = 0; i < sample_number; i++) {number_of_samples[i].data_in_sample[j] = (number_of_samples[i].data_in_sample[j] - min) / (max - min);} } } } void Data_type :: acquire_net_info(int signal, int no_output_nodes) { signal_dimensions = signal; nodes_in_output_layer = no_output_nodes; } void Data_type :: load_data_into_array(void) { // open the file containing the data ifstream file_ptr; // pointer to a file int i; file_ptr.open(filename, ios::in); // create dynamic array to hold the specified number of samples number_of_samples = new sample_data[sample_number]; for(i = 0; i < sample_number; i++) // create a dynamic array to hold the dimensions of each signal {number_of_samples[i].data_in_sample = new float[signal_dimensions + nodes_in_output_layer];} int dimensions = signal_dimensions + nodes_in_output_layer; //read in data from file and place in array for(i = 0; i < sample_number; i++) { for(int j = 0; j < dimensions; j++) {file_ptr >> number_of_samples[i].data_in_sample[j];} } file_ptr.close(); cout << "\n"; } void Data_type::delete_signal_array(void) {delete [] number_of_samples;} class signal_data // Class for randomizing the input signals { public: int signal_value; float signal_rank; }; class Training : public Data_type // Derived Class For Training Data { public: void request_training_data(int net_no); // Function to request data for training int number_of_epochs; signal_data *signalpoint; float rate_of_learning; // learning rate constant used by the net char presentation_order; // determines fixed or random signal presentation void scramble_data_in_array(void); float minimum_average_squared_error; void delete_signal_data_array(void); ~Training(); }; Training::~Training() { delete [] signalpoint; delete [] max_output_value; delete [] min_output_value; } void Training::request_training_data(int net_no) { cout << "Please enter the file name containing the training data for neural net no. "<< net_no << "\n"; cin >> filename; specify_signal_sample_size(); signalpoint = new signal_data[sample_number]; for(int i = 0; i < sample_number; i++) {signalpoint[i].signal_value = i;} normalize_data_in_array(); } void Training::scramble_data_in_array(void) { int swap1, swap2, hold_sample; float hold_rank; // randomly assign rank to all signals for(int sig = 0; sig < sample_number; sig ++) {signalpoint[sig].signal_rank = bedlam((long*)(gaset));} // reorder signals according to rank for(swap1 = 0; swap1 < sample_number - 1; swap1++) { for(swap2 = swap1 + 1; swap2 < sample_number; swap2++) { if(signalpoint[swap1].signal_rank > signalpoint[swap2].signal_rank) { hold_sample = signalpoint[swap2].signal_value; hold_rank = signalpoint[swap2].signal_rank; signalpoint[swap2].signal_value = signalpoint[swap1].signal_value; signalpoint[swap2].signal_rank = signalpoint[swap1].signal_rank; signalpoint[swap1].signal_value = hold_sample; signalpoint[swap1].signal_rank = hold_rank; } } } } void Training::delete_signal_data_array(void) { delete [] signalpoint; delete_signal_array(); } class Testing : public Training // Derived Class For Testing Data { public: void request_testing_data(int net_no, int test); // Function to request data for testing float average_squared_error; }; void Testing::request_testing_data(int net_no, int test) { cout << "Please enter the file name containing the testing data for neural net no. "<< net_no << "\n\n"; cin >> filename; cout << "\n\n"; cout << "For test #" << test + 1 << ":"; cout << "\n\n"; specify_signal_sample_size(); normalize_data_in_array(); } //************************************************************************// class NeuralB // class containing neural net structure for backpropagation { // along with training and testing data private: Training Training_Data; // file name and dynamic array for training Testing *Test_Data; // files containing data to test the network void initialize_training_storage_array(int N); void establish_test_battery_size(void); void train_net_with_backpropagation(void); void test_neural_network(int BNET); public: Back_Topology Net_Design; // specifications for backpropagating network int number_of_tests; void establish_backprop_network(void); void network_training_testing(int TT); ~NeuralB(); }; //************************************************************************// // these Neural class member function transmits data from the topology // to the data storage arrays NeuralB:: ~NeuralB() {delete [] Test_Data;} void NeuralB :: initialize_training_storage_array(int N) { Training_Data.acquire_net_info(Net_Design.signal_dimensions, Net_Design.nodes_in_output_layer); Training_Data.request_training_data(N); } void NeuralB :: establish_test_battery_size(void) { clrscr(); cout << "Please enter the number of tests you wish to run on the BP neural net: "; cin >> number_of_tests; cout << "\n"; if(number_of_tests > 0) { Test_Data = new Testing[number_of_tests]; for(int i = 0; i < number_of_tests; i++) {Test_Data[i].acquire_net_info(Net_Design.signal_dimensions, Net_Design.nodes_in_output_layer);} } } // define the establish_backprop_network function void NeuralB::establish_backprop_network(void) { clrscr(); cout << " **** Feedforward network using backpropagation **** " << "\n\n\n"; Net_Design.construct_and_initialize_backprop_network(); } // end establish_backprop_network function // set the activation functions of the nodes of the network // define train_net_with_backpropagation function void NeuralB::train_net_with_backpropagation(void) { char savefile; float output_error, sum_of_error, real_error_difference, target_minimum_average_squared_error; int sig, layers, sigdim, epoch, hidnode, hidnode2, outnode; int loopexit = 0; float *maxdifference; float *meandifference; ofstream savefile_ptr; clrscr(); cout << "please enter the number of epochs you wish to use for training: "; cin >> Training_Data.number_of_epochs; cout<< "\n"; cout << "please enter the learning rate constant for backpropagation (0-1): "; cin >> Training_Data.rate_of_learning; cout << "\n"; cout << "please enter the minimum average squared error you wish to target" << "\n"; cin >> target_minimum_average_squared_error; cout << "\n"; do { cout << "do you wish to save the mean error, maximum error" << "\n"; cout << "and average squared error for each epoch to a file? (Y or N): "; cin >> savefile; savefile = toupper(savefile); if((savefile == 'Y') || (savefile == 'N')) {loopexit = 2;} cout << "\n"; } while(loopexit <= 1); if(savefile == 'Y') { cout << "please enter the name of the file which will hold the results of training:" << "\n"; cin >> Training_Data.resultsname; cout <<"\n"; savefile_ptr.open(Training_Data.resultsname, ios::out); } cout << "Do you want signal presentation in random or fixed order(R or F): "; cin >> Training_Data.presentation_order; cout << "\n"; Training_Data.presentation_order = toupper(Training_Data.presentation_order); cout << "\n"; maxdifference = new float[Net_Design.nodes_in_output_layer]; meandifference = new float[Net_Design.nodes_in_output_layer]; // intiate backpropagation for appropriate number of epochs epoch = 0; do { sum_of_error = 0; for(sig = 0; sig < Training_Data.sample_number; sig++) { output_error = 0; for(sigdim = 0; sigdim < Training_Data.signal_dimensions; sigdim++) { if(Net_Design.number_of_hidden_layers == 0) // no hidden layers present { for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++) {Net_Design.node_in_output_layer[outnode].processing_unit_input[sigdim] = Training_Data.number_of_samples[Training_Data.signalpoint[sig].signal_value].data_in_sample[sigdim];} } else // 1 or 2 hidden layers present { for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[0].nodes_in_hidden_layer; hidnode++) {Net_Design.hidden_layer_number[0].node_in_hidden_layer[hidnode].processing_unit_input[sigdim] = Training_Data.number_of_samples[Training_Data.signalpoint[sig].signal_value].data_in_sample[sigdim];} } } if(Net_Design.number_of_hidden_layers == 2) // two layers are present { for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[0].nodes_in_hidden_layer; hidnode++) { Net_Design.hidden_layer_number[0].node_in_hidden_layer[hidnode].calculate_output_signal(Net_Design.activation_function_for_hidden_layer); for(hidnode2 = 0; hidnode2 < Net_Design.hidden_layer_number[1].nodes_in_hidden_layer; hidnode2++) {Net_Design.hidden_layer_number[1].node_in_hidden_layer[hidnode2].processing_unit_input[hidnode] = Net_Design.hidden_layer_number[0].node_in_hidden_layer[hidnode].output_signal;} } } if(Net_Design.number_of_hidden_layers > 0) { for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers -1].nodes_in_hidden_layer; hidnode++) { Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers -1].node_in_hidden_layer[hidnode].calculate_output_signal(Net_Design.activation_function_for_hidden_layer); for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++) {Net_Design.node_in_output_layer[outnode].processing_unit_input[hidnode] = Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers -1].node_in_hidden_layer[hidnode].output_signal;} } } for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++) { Net_Design.node_in_output_layer[outnode].calculate_output_signal(Net_Design.activation_function_for_output_layer); Net_Design.node_in_output_layer[outnode].calculate_output_error_information_term(Training_Data.number_of_samples[Training_Data.signalpoint[sig].signal_value].data_in_sample[Training_Data.signal_dimensions + outnode], Net_Design.activation_function_for_output_layer); // calculate the instantaneous sum of squared errors (Haykin, 1994) real_error_difference = (pow(Net_Design.node_in_output_layer[outnode].error_difference_squared, 0.5)) * (Training_Data.max_output_value[outnode] - Training_Data.min_output_value[outnode]); output_error += 0.5 * pow(real_error_difference, 2.0); // calculate maximum and mean absolute error difference for each node real_error_difference = Net_Design.node_in_output_layer[outnode].absolute_error_difference * (Training_Data.max_output_value[outnode] - Training_Data.min_output_value[outnode]); meandifference[outnode] += real_error_difference / float(Training_Data.sample_number); if(sig == 0) {maxdifference[outnode] = real_error_difference;} else { if(real_error_difference > maxdifference[outnode]) {maxdifference[outnode] = real_error_difference;} } } // average squared error for each signal is saved sum_of_error += output_error / float (Training_Data.sample_number); // backpropagation of error will depend on the number of hidden layers if(Net_Design.number_of_hidden_layers > 0) { // backpropagate from output node to adjacent hidden layer for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++) { for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers - 1].nodes_in_hidden_layer; hidnode++) {Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers - 1].node_in_hidden_layer[hidnode].error_information_term += Net_Design.node_in_output_layer[outnode].error_information_term * Net_Design.node_in_output_layer[outnode].weight_of_inputs[hidnode];} } // calculate error information term for each node in hiddenlayer for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers - 1].nodes_in_hidden_layer; hidnode++) {Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers - 1].node_in_hidden_layer[hidnode].calculate_hidden_error_information_term(Net_Design.activation_function_for_hidden_layer);} if(Net_Design.number_of_hidden_layers > 1) { // backpropagate error from hidden layer 2 to hidden layer 1 for(hidnode2 = 0; hidnode2 < Net_Design.hidden_layer_number[1].nodes_in_hidden_layer; hidnode2++) { for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[0].nodes_in_hidden_layer; hidnode++) {Net_Design.hidden_layer_number[0].node_in_hidden_layer[hidnode].error_information_term += Net_Design.hidden_layer_number[1].node_in_hidden_layer[hidnode2].error_information_term * Net_Design.hidden_layer_number[1].node_in_hidden_layer[hidnode2].weight_of_inputs[hidnode];} } for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[0].nodes_in_hidden_layer; hidnode++) {Net_Design.hidden_layer_number[0].node_in_hidden_layer[hidnode].calculate_hidden_error_information_term(Net_Design.activation_function_for_hidden_layer);} } } // update the networks output nodes for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++) {Net_Design.node_in_output_layer[outnode].calculate_weight_and_bias_correction_terms(Training_Data.rate_of_learning);} // update the networks hidden nodes (if they exist) if(Net_Design.number_of_hidden_layers > 0) { for(layers = 0; layers < Net_Design.number_of_hidden_layers; layers++) { for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[layers].nodes_in_hidden_layer; hidnode++) {Net_Design.hidden_layer_number[layers].node_in_hidden_layer[hidnode].calculate_weight_and_bias_correction_terms(Training_Data.rate_of_learning);} } } } // end sig loop // save error information (if required) if(savefile == 'Y') { savefile_ptr << epoch + 1 << " "; savefile_ptr << sum_of_error << " "; for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++) {savefile_ptr << maxdifference[outnode] << " " << meandifference[outnode] << " ";} savefile_ptr << endl; cout.width(6); clrscr(); cout << "Epoch #"<< epoch + 1 <<" is completed " << endl; } if(epoch == 0) {Training_Data.minimum_average_squared_error = sum_of_error;} else { if(sum_of_error < Training_Data.minimum_average_squared_error) {Training_Data.minimum_average_squared_error = sum_of_error;} } // scramble the order of signal presentation (if required) if(Training_Data.presentation_order == 'R') {Training_Data.scramble_data_in_array();} for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++) { maxdifference[outnode] = 0.0; meandifference[outnode] = 0.0;} if(Training_Data.minimum_average_squared_error <= target_minimum_average_squared_error) {break;} epoch = epoch + 1; } while(epoch < Training_Data.number_of_epochs); savefile_ptr.close(); // delete arrays holding the training data Training_Data.delete_signal_data_array(); delete [] maxdifference; delete [] meandifference; } // end of backpropagation function // define the function that tests the neural network void NeuralB::test_neural_network(int BNET) { float output_error, sum_of_error, real_output; int sig, sigdim, hidnode, hidnode2, outnode; int bnet = BNET; for(int t = 0; t < number_of_tests; t++) { Test_Data[t].request_testing_data(bnet, t); sum_of_error = 0; cout << "please enter the name of the file wich will hold the results of test: "<< t+1 << "\n"; cin >> Test_Data[t].resultsname; cout <<"\n"; ofstream savefile_ptr(Test_Data[t].resultsname); for(sig = 0; sig < Test_Data[t].sample_number; sig++) { output_error = 0; savefile_ptr << sig + 1 << " "; for(sigdim = 0; sigdim < Test_Data[t].signal_dimensions; sigdim++) { if(Net_Design.number_of_hidden_layers == 0) // no hidden layers present { for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++) {Net_Design.node_in_output_layer[outnode].processing_unit_input[sigdim] = Test_Data[t].number_of_samples[sig].data_in_sample[sigdim];} } else // 1 or 2 hidden layers present { for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[0].nodes_in_hidden_layer; hidnode++) {Net_Design.hidden_layer_number[0].node_in_hidden_layer[hidnode].processing_unit_input[sigdim] = Test_Data[t].number_of_samples[sig].data_in_sample[sigdim];} } } if(Net_Design.number_of_hidden_layers == 2) // two layers are present { for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[0].nodes_in_hidden_layer; hidnode++) { Net_Design.hidden_layer_number[0].node_in_hidden_layer[hidnode].calculate_output_signal(Net_Design.activation_function_for_hidden_layer); for(hidnode2 = 0; hidnode2 < Net_Design.hidden_layer_number[1].nodes_in_hidden_layer; hidnode2++) {Net_Design.hidden_layer_number[1].node_in_hidden_layer[hidnode2].processing_unit_input[hidnode] = Net_Design.hidden_layer_number[0].node_in_hidden_layer[hidnode].output_signal;} } } if(Net_Design.number_of_hidden_layers > 0) { for(hidnode = 0; hidnode < Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers -1].nodes_in_hidden_layer; hidnode++) { Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers -1].node_in_hidden_layer[hidnode].calculate_output_signal(Net_Design.activation_function_for_hidden_layer); for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++) {Net_Design.node_in_output_layer[outnode].processing_unit_input[hidnode] = Net_Design.hidden_layer_number[Net_Design.number_of_hidden_layers -1].node_in_hidden_layer[hidnode].output_signal;} } } for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++) { Net_Design.node_in_output_layer[outnode].calculate_output_signal(Net_Design.activation_function_for_output_layer); Net_Design.node_in_output_layer[outnode].calculate_output_error_information_term(Test_Data[t].number_of_samples[sig].data_in_sample[Test_Data[t].signal_dimensions + outnode], Net_Design.activation_function_for_output_layer); } // convert normalized target output data and send to file for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++) { real_output = Test_Data[t].min_output_value[outnode] + (Test_Data[t].number_of_samples[sig].data_in_sample[outnode + Test_Data[t].signal_dimensions] * (Test_Data[t].max_output_value[outnode] - Test_Data[t].min_output_value[outnode])); savefile_ptr << real_output << " "; } savefile_ptr << " "; // convert normalized output data and send to file for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++) { real_output = Test_Data[t].min_output_value[outnode] + (Net_Design.node_in_output_layer[outnode].output_signal * (Test_Data[t].max_output_value[outnode] - Test_Data[t].min_output_value[outnode])); savefile_ptr << real_output << " "; } // send absolute differences between each node and its output to a file for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++) { real_output = (pow(Net_Design.node_in_output_layer[outnode].error_difference_squared, 0.5)) * (Test_Data[t].max_output_value[outnode] - Test_Data[t].min_output_value[outnode]); savefile_ptr << real_output << " "; real_output = pow(real_output, 2.0); output_error += 0.5 * real_output; } // sum square of error savefile_ptr << output_error << "\n"; if(sig == Test_Data[t].sample_number - 1) {savefile_ptr.close();} sum_of_error += output_error; } Test_Data[t].average_squared_error = sum_of_error / Test_Data[t].sample_number; Test_Data[t].delete_signal_array(); } } // end test neural network function void NeuralB::network_training_testing(int TT) { int tt = TT; int menu_choice; clrscr(); cout << "\n\n\n\n"; cout << "**************** Operations Menu ****************" << "\n\n"; cout << " Please select one of the following options:" <<"\n\n"; cout << " 1. Train Backprop network only " <<"\n\n"; cout << " 2. Test Backprop network only " <<"\n\n"; cout << " 3. Train and Test Backprop network" <<"\n\n"; cout << "*************************************************" << "\n\n"; cout << " Your choice?: "; cin >> menu_choice; cout << "\n\n"; switch(menu_choice) { case 1: initialize_training_storage_array(tt); train_net_with_backpropagation(); break; case 2: establish_test_battery_size(); if(number_of_tests > 0) {test_neural_network(tt);} break; case 3: initialize_training_storage_array(tt); train_net_with_backpropagation(); establish_test_battery_size(); if(number_of_tests > 0) {test_neural_network(tt);} break; default:network_training_testing(tt); } } // This concludes the backpropagation section of the program //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // (ART 1) Define base class for Interface and Cluster units of the // Adaptive Resonance Theory Neural Network 1 class ART_units { public: float *input_value; float *output_value; float *input_weight_vector; int number_of_inputs; int number_of_outputs; float activation; void establish_input_output_arrays(void); virtual void establish_input_weight_vector_array(void); virtual void initialize_inputs_and_weights(void); ~ART_units(); }; ART_units::~ART_units() { delete [] input_value; delete [] output_value; delete [] input_weight_vector; } void ART_units::establish_input_output_arrays(void) { input_value = new float[number_of_inputs]; output_value = new float[number_of_outputs]; } void ART_units::establish_input_weight_vector_array(void) {input_weight_vector = new float[number_of_inputs - 1];} void ART_units::initialize_inputs_and_weights(void) { for(int w = 0; w < number_of_inputs - 1; w++) {input_weight_vector[w] = 1.0;} for(int c = 1; c < number_of_inputs; c++) {input_value[c] = 0.0;} activation = 0.0; } // establish Interface node attributes class Interface_units: public ART_units { public: void recompute_activation(int winning_cluster); void calculate_output_value(int G1); }; void Interface_units::recompute_activation(int winning_cluster) {activation = input_value[0] * input_weight_vector[winning_cluster];} void Interface_units::calculate_output_value(int G1) { float feedback_signal, node_output, two_thirds_rule; feedback_signal = 0.0; // calculate feedback signal through use of weighted sum for(int f = 0; f < number_of_inputs-1; f++) {feedback_signal+=input_weight_vector[f]*input_value[f+1];} two_thirds_rule = feedback_signal + input_value[0] + float(G1); // use Two Thirds Rule to determine node output if(two_thirds_rule >= 2.0) {node_output = 1.0;} else {node_output = 0.0;} // establish output vector to cluster units for(int p = 0; p < number_of_outputs; p++) {output_value[p] = node_output;} } // establish Cluster node attributes class Cluster_units: public ART_units { public: int cluster_tag; float net_input; void establish_input_weight_vector_array(void); void initialize_inputs_and_weights(void); void calculate_net_input(void); void establish_node_output(void); Cluster_units(); // default constructor }; Cluster_units::Cluster_units() {cluster_tag = 0;} void Cluster_units::establish_input_weight_vector_array(void) {input_weight_vector = new float[number_of_inputs];} void Cluster_units::initialize_inputs_and_weights(void) { for(int c = 0; c < number_of_inputs; c++) {input_weight_vector[c] = 1.0 / (1.0 + number_of_inputs);} } void Cluster_units::calculate_net_input(void) { net_input = 0.0; for(int n = 0; n < number_of_inputs; n++) {net_input += input_value[n] * input_weight_vector[n];} } void Cluster_units::establish_node_output(void) { for(int oput = 0; oput < number_of_outputs - 1; oput++) if(activation >= 0.0) {output_value[oput] = activation;} else {output_value[oput] = 0.0;} } // establish Inputs unit attributes class Input_units {public: float signal_value;}; // establish ART1 neural network attributes class ART_Topology { public: char netcreate; int clustercount; int dimensions_of_signal; int number_of_cluster_units; int reset_value; int resetcount; float vigilance_parameter; float norm_of_activation_vector; float norm_of_input_vector; float weight_update_parameter; int cluster_champ; int clusterange; Input_units *node_in_input_layer; Interface_units *node_in_interface_layer; Cluster_units *node_in_cluster_layer; void establish_net_topology(void); void upload_network(void); void transmit_pattern_to_interface(void); void transmit_pattern_to_cluster(void); void broadcast_output_to_cluster_layer(void); void cluster_nodes_compete_for_activation(int train_or_test); void compute_norm_of_activation_vector(void); void compute_norm_of_input_vector(void); void recompute_activation_vector_of_interface_layer(void); void update_the_network(void); void set_cluster_activation_to_zero(void); void savenet(void); ART_Topology(); ~ART_Topology(); // class destructor }; ART_Topology::ART_Topology() { clustercount = 0; clusterange = 0; resetcount = 0; } ART_Topology::~ART_Topology() { delete [] node_in_input_layer; delete [] node_in_interface_layer; delete [] node_in_cluster_layer; } void ART_Topology::establish_net_topology(void) { weight_update_parameter = 2.0; node_in_input_layer = new Input_units[dimensions_of_signal]; node_in_interface_layer = new Interface_units[dimensions_of_signal]; node_in_cluster_layer = new Cluster_units[number_of_cluster_units]; // Establish interface layer of ART1 network for(int I = 0; I < dimensions_of_signal; I++) { node_in_interface_layer[I].number_of_inputs = number_of_cluster_units + 1; node_in_interface_layer[I].number_of_outputs = number_of_cluster_units; node_in_interface_layer[I].establish_input_output_arrays(); node_in_interface_layer[I].establish_input_weight_vector_array(); node_in_interface_layer[I].initialize_inputs_and_weights(); } // Establish cluster layer of ART1 network for(int C = 0; C < number_of_cluster_units; C++) { node_in_cluster_layer[C].number_of_inputs = dimensions_of_signal; node_in_cluster_layer[C].number_of_outputs = dimensions_of_signal + 1; node_in_cluster_layer[C].establish_input_output_arrays(); node_in_cluster_layer[C].establish_input_weight_vector_array(); node_in_cluster_layer[C].initialize_inputs_and_weights(); } } void ART_Topology::upload_network(void) { char getname[13]; ifstream get_ptr; int netid, node, dim; int dolock = 0; do { cout << "\n\n"; cout << "Please enter the name of the file which holds the ART1 Network" << "\n"; cin >> getname; cout << "\n"; get_ptr.open(getname, ios::in); get_ptr >> netid; if(netid == 2) {dolock = 1;} else { cout << "Error** file contents do not match ART1 specifications" << "\n"; cout << "try again" << "\n"; get_ptr.close(); } } while(dolock <= 0); get_ptr >> dimensions_of_signal; get_ptr >> weight_update_parameter; get_ptr >> vigilance_parameter; get_ptr >> clusterange; get_ptr >> clustercount; get_ptr >> number_of_cluster_units; node_in_input_layer = new Input_units[dimensions_of_signal]; node_in_interface_layer = new Interface_units[dimensions_of_signal]; node_in_cluster_layer = new Cluster_units[number_of_cluster_units]; for(node = 0; node < dimensions_of_signal; node++) { node_in_interface_layer[node].number_of_inputs = number_of_cluster_units + 1; node_in_interface_layer[node].number_of_outputs = number_of_cluster_units; node_in_interface_layer[node].establish_input_output_arrays(); node_in_interface_layer[node].establish_input_weight_vector_array(); node_in_interface_layer[node].initialize_inputs_and_weights(); for(dim = 1; dim < number_of_cluster_units + 1; dim++) {get_ptr >> node_in_interface_layer[node].input_weight_vector[dim];} } for(node = 0; node < number_of_cluster_units; node++) { node_in_cluster_layer[node].number_of_inputs = dimensions_of_signal; node_in_cluster_layer[node].number_of_outputs = dimensions_of_signal + 1; node_in_cluster_layer[node].establish_input_output_arrays(); node_in_cluster_layer[node].establish_input_weight_vector_array(); node_in_cluster_layer[node].initialize_inputs_and_weights(); get_ptr >> node_in_cluster_layer[node].cluster_tag; for(dim = 0; dim < dimensions_of_signal; dim++) {get_ptr >> node_in_cluster_layer[node].input_weight_vector[dim];} } get_ptr.close(); } void ART_Topology::transmit_pattern_to_interface(void) { for(int d = 0; d < dimensions_of_signal; d++) { node_in_interface_layer[d].input_value[0] = node_in_input_layer[d].signal_value; node_in_interface_layer[d].activation = node_in_input_layer[d].signal_value; } } void ART_Topology::transmit_pattern_to_cluster(void) { int c; for(int d = 0; d < dimensions_of_signal; d++) { for(c = 0; c < number_of_cluster_units; c++) {node_in_cluster_layer[c].input_value[d] = node_in_input_layer[d].signal_value;} } } void ART_Topology::broadcast_output_to_cluster_layer(void) { int Gain_one; int cluster_active = 0; int d, c; for(c = 0; c < number_of_cluster_units; c++) {if(node_in_cluster_layer[c].activation == 1.0) {cluster_active = 1;} } compute_norm_of_input_vector(); if((cluster_active != 1) && (norm_of_input_vector > 0.0)) {Gain_one = 1;} else {Gain_one = 0;} // establish interface output vector for(d = 0; d < dimensions_of_signal; d++) {node_in_interface_layer[d].calculate_output_value(Gain_one);} //transmit interface output to units in cluster layer for(d = 0; d < dimensions_of_signal; d++) { for(c = 0; c < number_of_cluster_units; c++) {node_in_cluster_layer[c].input_value[d] = node_in_interface_layer[d].output_value[c];} } } void ART_Topology::cluster_nodes_compete_for_activation(int train_or_test) { int d, cluster; float champion = 0.0; for(cluster = 0; cluster < clusterange + 1; cluster++) { if(node_in_cluster_layer[cluster].activation != -1.0) { node_in_cluster_layer[cluster].calculate_net_input(); if(node_in_cluster_layer[cluster].net_input > champion) { champion = node_in_cluster_layer[cluster].net_input; cluster_champ = cluster; } } } if((node_in_cluster_layer[cluster_champ].cluster_tag == 0) && (train_or_test < 2)) { node_in_cluster_layer[cluster_champ].cluster_tag = clustercount + 1; clustercount = clustercount + 1; } if(train_or_test < 2) { for(cluster = 0; cluster < clusterange + 1; cluster++) { if(cluster == cluster_champ) {node_in_cluster_layer[cluster].activation = 1.0;} else { if(node_in_cluster_layer[cluster].activation != -1.0) {node_in_cluster_layer[cluster].activation = 0.0;} } node_in_cluster_layer[cluster].establish_node_output(); // send output signals to Interface layer for(d = 0; d < dimensions_of_signal; d++) {node_in_interface_layer[d].input_value[cluster + 1] = node_in_cluster_layer[cluster].output_value[d];} } } } void ART_Topology::compute_norm_of_activation_vector(void) { norm_of_activation_vector = 0.0; for(int d = 0; d < dimensions_of_signal; d++) {norm_of_activation_vector += node_in_interface_layer[d].activation;} compute_norm_of_input_vector(); } void ART_Topology::compute_norm_of_input_vector(void) { norm_of_input_vector = 0.0; for(int d = 0; d < dimensions_of_signal; d++) {norm_of_input_vector += node_in_input_layer[d].signal_value;} } void ART_Topology::recompute_activation_vector_of_interface_layer(void) { for(int d = 0; d < dimensions_of_signal; d++) {node_in_interface_layer[d].recompute_activation(cluster_champ);} } void ART_Topology:: update_the_network(void) { recompute_activation_vector_of_interface_layer(); compute_norm_of_activation_vector(); float ratio_test = norm_of_activation_vector / norm_of_input_vector; if(ratio_test < vigilance_parameter) { node_in_cluster_layer[cluster_champ].activation = -1.0; reset_value = 1; resetcount += reset_value; if(resetcount == number_of_cluster_units - 1) { clusterange = clusterange + 1; if(clusterange > number_of_cluster_units) {clusterange = number_of_cluster_units;} } } else { // update the weights of the champion cluster unit for(int u = 0; u < node_in_cluster_layer[cluster_champ].number_of_inputs; u++) {node_in_cluster_layer[cluster_champ].input_weight_vector[u] = (weight_update_parameter * node_in_interface_layer[u].activation * node_in_cluster_layer[cluster_champ].input_weight_vector[u]) / ((weight_update_parameter - 1.0) + norm_of_activation_vector);} for(int n = 0; n < dimensions_of_signal; n++) {node_in_interface_layer[n].input_weight_vector[cluster_champ] = node_in_interface_layer[n].input_weight_vector[cluster_champ] * node_in_interface_layer[n].activation;} reset_value = 0; resetcount = 0; } } void ART_Topology::set_cluster_activation_to_zero(void) { for(int cnode = 0; cnode < clusterange + 1; cnode++) {node_in_cluster_layer[cnode].activation = 0.0;} } void ART_Topology::savenet(void) { char savename[13]; ofstream save_ptr; int node, dim; cout << "\n\n"; cout << "Please enter the name of the file which will hold the ART network"<<"\n"; cin >> savename; cout <<"\n"; save_ptr.open(savename, ios::out); save_ptr << 2 << "\n"; //network identifier number save_ptr << dimensions_of_signal << "\n"; save_ptr << weight_update_parameter << "\n"; save_ptr << vigilance_parameter << "\n"; save_ptr << clusterange << "\n"; save_ptr << clustercount << "\n"; save_ptr << number_of_cluster_units << "\n"; for(node = 0; node < dimensions_of_signal; node++) { for(dim = 1; dim < number_of_cluster_units + 1; dim++) {save_ptr << node_in_interface_layer[node].input_weight_vector[dim] << " ";} save_ptr << "\n"; } for(node = 0; node < number_of_cluster_units; node++) { save_ptr << node_in_cluster_layer[node].cluster_tag << "\n"; for(dim = 0; dim < dimensions_of_signal; dim++) {save_ptr << node_in_cluster_layer[node].input_weight_vector[dim] << " ";} save_ptr << "\n"; } save_ptr.close(); } // Classes which specifies the containers of ART training and test data class ART_Training_Data : public Data_type { public: void determine_sample_number(void); void load_data_into_array(void); virtual void request_ART_data(int net_no); }; void ART_Training_Data::load_data_into_array(void) { int d, i; float dimensions; // open the file containing the data ifstream Afile_ptr; // pointer to a file Afile_ptr.open(filename, ios::in); //create a dynamic array to hold the specified number of samples number_of_samples = new sample_data[sample_number]; for(i = 0; i < sample_number; i++) {number_of_samples[i].data_in_sample = new float[signal_dimensions];} // read in data from file and place in array for(i = 0; i < sample_number; i++) { for(d = 0; d < signal_dimensions; d++) { Afile_ptr >> dimensions; number_of_samples[i].data_in_sample[d] = dimensions; } } Afile_ptr.close(); } void ART_Training_Data :: determine_sample_number(void) { ifstream dfile_ptr; // pointer to a file dfile_ptr.open(filename, ios::in); float hold; int lock = 1; sample_number = 0; do { if(dfile_ptr.eof()){lock = 0;} else {dfile_ptr >> hold; sample_number += 1;} }while(lock > 0); dfile_ptr.close(); sample_number = int(sample_number / signal_dimensions); } void ART_Training_Data::request_ART_data(int net_no) { cout << "Please enter the file name containing the training data for ART network no. "<< net_no << "\n"; cin >> filename; cout << "\n"; specify_signal_sample_size(); } class ART_Test_Data : public ART_Training_Data {public: void request_ART_data(int net_no);}; void ART_Test_Data::request_ART_data(int net_no) { cout << "Please enter the file name containing the test data for ART network no. " << net_no << "\n"; cin >> filename; cout << "\n"; specify_signal_sample_size(); } //************************************************************************// class NeuralA // class containing the ART1 neural net structure { // along with training and testing data private: ART_Training_Data ART_Train; ART_Test_Data * ART_Test; // the number of test is variable int number_of_ART_tests; void initialize_ART_training_storage_array(int AN); void establish_ART_test_battery_size(void); void train_ART_network(int ARTN); void test_ART_network(int ANET); public: ART_Topology ART_Design; void construct_ART_network(void); void network_training_testing(int TT); ~NeuralA(); }; //****************************************************************************// NeuralA::~NeuralA() { delete [] ART_Test; } void NeuralA::construct_ART_network(void) { int looploc = 0; clrscr(); cout << " **** Adaptive Resonance Theory network for binary signals **** " <<"\n\n\n"; do { cout <<"\n"; cout << "Do you wish to" << "\n\n"; cout << "C. Create your own ART1 Network " << "\n"; cout << "U. Upload an existing ART1 Network " << "\n\n"; cout << "Your choice?: "; cin >> ART_Design.netcreate; cout << "\n\n"; ART_Design.netcreate = toupper(ART_Design.netcreate); if((ART_Design.netcreate == 'C') || (ART_Design.netcreate == 'U')) {looploc = 1;} } while(looploc <= 0); if(ART_Design.netcreate == 'U') {ART_Design.upload_network();} else { cout << "\n"; cout << "Please enter the dimensions of the ART network's input signal vector: "; cin >> ART_Design.dimensions_of_signal; cout << "\n"; cout << "Please enter the vigilance parameter of the ART network: "; cin >> ART_Design.vigilance_parameter; cout << "\n"; } } void NeuralA::initialize_ART_training_storage_array(int AN) { int AT = AN; ART_Train.acquire_net_info(ART_Design.dimensions_of_signal, ART_Design.number_of_cluster_units); ART_Train.request_ART_data(AT); if(ART_Design.netcreate == 'C') // constructing new network { ART_Design.number_of_cluster_units = ART_Train.sample_number; ART_Design.establish_net_topology(); } } void NeuralA::train_ART_network(int ARTN) { int dim, nodes_available_for_clustering; char savetrain; int dolock = 0; clrscr(); cout << "\n\n"; cout << "For Neural Network #" << ARTN << "\n"; do { cout << "do you wish to save the ART Training results to a file? (Y or N): "; cin >> savetrain; savetrain = toupper(savetrain); if((savetrain == 'N') || (savetrain == 'Y')) {dolock = 1;} cout << "\n"; } while(dolock <= 0); if(savetrain == 'Y') { cout << "please enter the name of the file to hold the results of the ART Training" << "\n"; cin >> ART_Train.resultsname; cout << "\n"; } for(int pattern = 0; pattern < ART_Train.sample_number; pattern++) { // present pattern to input layer for(dim = 0; dim < ART_Design.dimensions_of_signal; dim++) {ART_Design.node_in_input_layer[dim].signal_value = ART_Train.number_of_samples[pattern].data_in_sample[dim];} nodes_available_for_clustering = ART_Design.number_of_cluster_units; do { ART_Design.transmit_pattern_to_interface(); ART_Design.broadcast_output_to_cluster_layer(); ART_Design.cluster_nodes_compete_for_activation(1); ART_Design.update_the_network(); nodes_available_for_clustering = nodes_available_for_clustering - ART_Design.reset_value; if(nodes_available_for_clustering < 1) // input pattern cannot be clustered { // clrscr(); cout << "Input pattern #" << pattern + 1 << ": "; for(dim = 0; dim < ART_Design.dimensions_of_signal; dim++) {cout << int(ART_Design.node_in_input_layer[dim].signal_value);} cout << " cannot be clustered" << "\n"; break; } } while (ART_Design.reset_value >=1); if(savetrain == 'Y') { ofstream ART_savefile_ptr(ART_Train.resultsname, ios::out|ios::app); ART_savefile_ptr << pattern + 1 << " "; for(dim = 0; dim < ART_Design.dimensions_of_signal; dim++) {ART_savefile_ptr << int(ART_Design.node_in_input_layer[dim].signal_value);} ART_savefile_ptr << " " << ART_Design.node_in_cluster_layer[ART_Design.cluster_champ].cluster_tag << "\n"; ART_savefile_ptr.close(); } ART_Design.set_cluster_activation_to_zero(); } // delete array containing training data ART_Train.delete_signal_array(); } void NeuralA::establish_ART_test_battery_size(void) { cout <<"Please enter the number of tests you wish to run on the ART neural network: "; cin >> number_of_ART_tests; cout <<"\n"; // create testing array if(number_of_ART_tests > 0) { ART_Test = new ART_Test_Data[number_of_ART_tests]; for(int t = 0; t < number_of_ART_tests; t++) {ART_Test[t].acquire_net_info(ART_Design.dimensions_of_signal, ART_Design.number_of_cluster_units);} } } void NeuralA::test_ART_network(int ANET) { int tnet, dim, pattern; tnet = ANET; for(int Atest = 0; Atest < number_of_ART_tests; Atest++) { ART_Test[Atest].request_ART_data(tnet); cout << "For ART1 neural network #" << ANET <<" and test #"<> ART_Test[Atest].resultsname; cout << "\n"; ofstream ART_savefile_ptr(ART_Test[Atest].resultsname); for(pattern = 0; pattern < ART_Test[Atest].sample_number; pattern++) { for(dim = 0; dim < ART_Design.dimensions_of_signal; dim++) {ART_Design.node_in_input_layer[dim].signal_value = ART_Test[Atest].number_of_samples[pattern].data_in_sample[dim];} ART_Design.transmit_pattern_to_cluster(); ART_Design.cluster_nodes_compete_for_activation(2); ART_savefile_ptr <> menu_choice; cout << "\n\n"; if((menu_choice == 2) && (ART_Design.netcreate == 'C')) {menu_choice = 3;} if((menu_choice == 3) && (ART_Design.netcreate == 'U')) {menu_choice = 3;} switch(menu_choice) { case 1: initialize_ART_training_storage_array(tt); train_ART_network(tt); break; case 2: establish_ART_test_battery_size(); if(number_of_ART_tests > 0) {test_ART_network(tt);} break; case 3: initialize_ART_training_storage_array(tt); train_ART_network(tt); establish_ART_test_battery_size(); if(number_of_ART_tests > 0) {test_ART_network(tt);} break; default:network_training_testing(tt); } } // This concludes the ART1 section of the program //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // (Kohonen) Define base class for the Clustering Nodes of // the Kohonen Self-Organizing Map //************************ ATTENTION ************************************ // Note that the Class Kohonen_units will also contain variables and // functions relevant to the Radial Basis Function Neural Network (RBFN) //*********************************************************************** class Kohonen_units: public ART_units { public: void establish_input_weight_vector_array(void); void initialize_inputs_and_weights(void); void calculate_sum_square_Euclidean_distance(void); void update_the_weights(float learning_rate); Kohonen_units(); // default constructor //******************************************************* float transfer_function_width; // RBFN float Gaussian_transfer_output; // RBFN void execute_Gaussian_transfer_function(void); // RBFN //******************************************************* }; Kohonen_units::Kohonen_units() {number_of_outputs = 1;} void Kohonen_units::establish_input_weight_vector_array(void) {input_weight_vector = new float[number_of_inputs];} void Kohonen_units::initialize_inputs_and_weights(void) { for(int k = 0; k < number_of_inputs; k++) {input_weight_vector[k] = bedlam((long*)(gaset));} } void Kohonen_units::calculate_sum_square_Euclidean_distance(void) { double sumsquare; float ss1; int ci; output_value[0] = 0.0; for(int k = 0; k < number_of_inputs; k++) { ci = k; if(input_value[ci] == 0.0) { sumsquare = pow(input_weight_vector[ci], 2.0); } else { sumsquare = pow(fabs(input_weight_vector[ci] - input_value[ci]), 2.0); } output_value[0] += sumsquare; // cout << output_value[0] << "\n"; // cin >> output_value[0]; } ss1 = output_value[0]; output_value[0] = sqrt(fabs(ss1)); } void Kohonen_units::update_the_weights(float learning_rate) { for(int k = 0; k < number_of_inputs; k++) {input_weight_vector[k] = input_weight_vector[k] + (learning_rate * (input_value[k] - input_weight_vector[k]));} } // RBFN // void Kohonen_units::execute_Gaussian_transfer_function(void) { float transfer_ratio = (-1.0) * pow((output_value[0] / transfer_function_width), 2.0); Gaussian_transfer_output = exp(transfer_ratio); } // define class and member functions which define Kohonen Topology class Kohonen_Topology { public: int kluster_champ; int dimensions_of_signal; int maximum_number_of_clusters; float max_learning_rate; float min_learning_rate; float interim_learning_rate; Kohonen_units *node_in_cluster_layer; void establish_Kohonen_topology(int netuse); void kluster_nodes_compete_for_activation(void); void update_the_Kohonen_network(int epoch_count, int max_epochs); virtual void upload_network(void); // retrieve network from file virtual void savenet(void); // save network to file Kohonen_Topology(); // class constructor ~Kohonen_Topology(); // class destructor }; Kohonen_Topology::Kohonen_Topology() {interim_learning_rate = 1.0;} Kohonen_Topology::~Kohonen_Topology() {delete [] node_in_cluster_layer;} void Kohonen_Topology::establish_Kohonen_topology(int netuse) { char netcreate; int looploc = 0; if(netuse == 1) { do { cout <<"\n"; cout << "Do you wish to" << "\n\n"; cout << "C. Create your own Kohonen Map " << "\n"; cout << "U. Upload an existing Kohonen Map " << "\n\n"; cout << "Your choice?: "; cin >> netcreate; cout << "\n\n"; netcreate = toupper(netcreate); if((netcreate == 'C') || (netcreate == 'U')) {looploc = 1;} } while(looploc <= 0); } else { netcreate = 'C'; } if((netcreate == 'U') && (netuse == 1)) {upload_network();} else { if(netuse == 1) { cout <<"Please enter the dimensions of the network's input signal vector: "; cin >> dimensions_of_signal; cout <<"\n"; } cout << "please enter the maximum number of clusters to be formed: "; cin >> maximum_number_of_clusters; cout << "\n"; // establish clustering layer of Kohonen network node_in_cluster_layer = new Kohonen_units[maximum_number_of_clusters]; for(int c = 0; c < maximum_number_of_clusters; c++) { node_in_cluster_layer[c].number_of_inputs = dimensions_of_signal; node_in_cluster_layer[c].establish_input_output_arrays(); node_in_cluster_layer[c].establish_input_weight_vector_array(); node_in_cluster_layer[c].initialize_inputs_and_weights(); } } } void Kohonen_Topology::upload_network(void) { char getname[13]; ifstream get_ptr; int netid, nodes, dim; int dolock = 0; do { cout << "\n\n"; cout << "Please enter the name of the file which holds the Kohonen Map" << "\n"; cin >> getname; cout << "\n"; get_ptr.open(getname, ios::in); get_ptr >> netid; if(netid == 3) {dolock = 1;} else { cout << "Error** file contents do not match Kohonen specifications" << "\n"; cout << "try again" << "\n"; get_ptr.close(); } } while(dolock <= 0); get_ptr >> dimensions_of_signal; get_ptr >> maximum_number_of_clusters; node_in_cluster_layer = new Kohonen_units[maximum_number_of_clusters]; for(nodes = 0; nodes < maximum_number_of_clusters; nodes++) { node_in_cluster_layer[nodes].number_of_inputs = dimensions_of_signal; node_in_cluster_layer[nodes].establish_input_output_arrays(); node_in_cluster_layer[nodes].establish_input_weight_vector_array(); } for(nodes = 0; nodes < maximum_number_of_clusters; nodes++) { for(dim = 0; dim < dimensions_of_signal; dim++) {get_ptr >> node_in_cluster_layer[nodes].input_weight_vector[dim];} } get_ptr.close(); } void Kohonen_Topology:: kluster_nodes_compete_for_activation(void) { float minimum_distance; for(int m = 0; m < maximum_number_of_clusters; m++) { node_in_cluster_layer[m].calculate_sum_square_Euclidean_distance(); if(m == 0) { kluster_champ = m; minimum_distance = node_in_cluster_layer[m].output_value[0]; } else { if(node_in_cluster_layer[m].output_value[0] < minimum_distance) { kluster_champ = m; minimum_distance = node_in_cluster_layer[m].output_value[0]; } } } } void Kohonen_Topology::update_the_Kohonen_network(int epoch_count, int max_epochs) { int maxepoch; if(max_epochs == 1) {maxepoch = 1;} else {maxepoch = max_epochs - 1;} float adjusted_learning_rate = max_learning_rate - (((max_learning_rate - min_learning_rate) / maxepoch) * epoch_count); interim_learning_rate = adjusted_learning_rate * interim_learning_rate; node_in_cluster_layer[kluster_champ].update_the_weights(interim_learning_rate); } void Kohonen_Topology::savenet(void) { char savename[13]; ofstream save_ptr; int node, dim; cout << "\n\n"; cout << "Please enter the name of the file which will hold the Kohonen Map" <<"\n"; cin >> savename; cout <<"\n"; save_ptr.open(savename, ios::out); save_ptr << 3 << "\n"; // network identifier number save_ptr << dimensions_of_signal << "\n"; save_ptr << maximum_number_of_clusters << "\n"; for(node = 0; node < maximum_number_of_clusters; node++) { for(dim = 0; dim < dimensions_of_signal; dim++) {save_ptr << node_in_cluster_layer[node].input_weight_vector[dim] << " ";} save_ptr <<"\n"; } save_ptr.close(); } // define class and member functions which define training and test data // storage for the Kohonen Self_Organizing Map class Kohonen_Training_Data : public ART_Training_Data { public: void acquire_net_info(int signal); void normalize_data_in_array(void); virtual void request_Kohonen_data(int net_no); }; void Kohonen_Training_Data::acquire_net_info(int signal) {signal_dimensions = signal;} void Kohonen_Training_Data::normalize_data_in_array(void) { int i, j, imax, imin; int trigger; float min, max; max_output_value = new float[signal_dimensions]; min_output_value = new float[signal_dimensions]; for(j = 0; j < signal_dimensions; j++) { trigger = 1; // identify minimum and maximum values for each dimension for(i = 0; i < sample_number; i++) { if(i == 0) { max = number_of_samples[i].data_in_sample[j]; min = number_of_samples[i].data_in_sample[j]; } else { if(number_of_samples[i].data_in_sample[j] < min) {min = number_of_samples[i].data_in_sample[j];} if(number_of_samples[i].data_in_sample[j] > max) {max = number_of_samples[i].data_in_sample[j];} } } // normalize the values in each dimension of the signal max_output_value[j] = max; min_output_value[j] = min; imax = int(max); imin = int(min); if((imax == 1) && (imin == 0) && (max <= 1.0) && (min <= 0.0)) {trigger = 0;} if((imax == 1) && (imin == 1) && (max <= 1.0) && (min <= 1.0)) {trigger = 0;} if((imax == 0) && (imin == 0) && (max <= 0.0) && (min <= 0.0)) {trigger = 0;} if(trigger != 0) // do not normalize binary signals { for(i = 0; i < sample_number; i++) {number_of_samples[i].data_in_sample[j] = (number_of_samples[i].data_in_sample[j] - min)/(max - min);} } } } void Kohonen_Training_Data::request_Kohonen_data(int net_no) { cout << "Enter the file name containing the training data for Kohonen network no. " <> filename; cout <<"\n"; specify_signal_sample_size(); normalize_data_in_array(); } class Kohonen_Test_Data: public Kohonen_Training_Data {public: void request_Kohonen_data(int net_no);}; void Kohonen_Test_Data::request_Kohonen_data(int net_no) { cout << "Please enter the file name containing the test data for Kohonen network no. " <> filename; cout <<"\n"; specify_signal_sample_size(); normalize_data_in_array(); } //************************************************************************// class NeuralK // class containing the Kohonen neural net structure { // along with training and testing data private: Kohonen_Training_Data Kohonen_Train; Kohonen_Test_Data *Kohonen_Test; // number of tests is variable int number_of_Kohonen_tests; void initialize_Kohonen_training_storage_array(int KN); void establish_Kohonen_test_battery_size(void); void train_Kohonen_network(int KOHN); void test_Kohonen_network(int KNET); public: Kohonen_Topology Kohonen_Design; void construct_Kohonen_network(void); void network_training_testing(int TT); ~NeuralK(); }; //*************************************************************************// NeuralK::~NeuralK() {delete [] Kohonen_Test;} void NeuralK::construct_Kohonen_network(void) { clrscr(); cout <<"**** Kohonen Self-Organizing Map ****"<< "\n\n\n"; Kohonen_Design.establish_Kohonen_topology(1); } void NeuralK::initialize_Kohonen_training_storage_array(int KN) { int KT = KN; Kohonen_Train.acquire_net_info(Kohonen_Design.dimensions_of_signal); Kohonen_Train.request_Kohonen_data(KT); } void NeuralK::establish_Kohonen_test_battery_size(void) { cout << "Please enter the number of tests you wish to run on the Kohonen Neural Network: "; cin >> number_of_Kohonen_tests; cout << "\n"; if(number_of_Kohonen_tests > 0) { // create testing array Kohonen_Test = new Kohonen_Test_Data[number_of_Kohonen_tests]; for(int t = 0; t < number_of_Kohonen_tests; t++) {Kohonen_Test[t].acquire_net_info(Kohonen_Design.dimensions_of_signal);} } } void NeuralK::train_Kohonen_network(int KOHN) { int dim, ep, k_epochs, pattern, knodes, dolock; clrscr(); cout <<"\n\n"; cout << "For Neural Network #"<> Kohonen_Design.max_learning_rate; cout <<"\n"; cout << "please enter the minimum learning rate parameter (0-1): "; cin >> Kohonen_Design.min_learning_rate; cout <<"\n"; cout << "please enter the number of epochs used to train the Kohonen Map: "; cin >> k_epochs; cout << "\n"; ep = 0; dolock = 0; do { for(pattern = 0; pattern < Kohonen_Train.sample_number; pattern++) { for(knodes = 0; knodes < Kohonen_Design.maximum_number_of_clusters; knodes++) { for(dim = 0; dim < Kohonen_Design.dimensions_of_signal; dim++) {Kohonen_Design.node_in_cluster_layer[knodes].input_value[dim] = Kohonen_Train.number_of_samples[pattern].data_in_sample[dim];} } Kohonen_Design.kluster_nodes_compete_for_activation(); Kohonen_Design.update_the_Kohonen_network(ep, k_epochs); } cout << "Epoch " << ep + 1 << " is completed" <<"\n"; if((ep == k_epochs - 1) || (Kohonen_Design.interim_learning_rate == 0.0)) {dolock = 1;} ep = ep + 1; } while(dolock <= 0); Kohonen_Train.delete_signal_array(); } void NeuralK::test_Kohonen_network(int KNET) { int tnet, dim, pattern, knodes; float realvalue; tnet = KNET; clrscr(); for(int ktest = 0; ktest < number_of_Kohonen_tests; ktest++) { Kohonen_Test[ktest].request_Kohonen_data(tnet); cout <<"For Kohonen neural network #"<< KNET <<" and test #"<< ktest+1 <<":" <<"\n"; cout <<"please enter the name of the file to hold the test" << "\n"; cin >> Kohonen_Test[ktest].resultsname; cout <<"\n"; ofstream Kohonen_savefile_ptr(Kohonen_Test[ktest].resultsname); for(pattern = 0; pattern < Kohonen_Test[ktest].sample_number; pattern++) { for(knodes = 0; knodes < Kohonen_Design.maximum_number_of_clusters; knodes++) { for(dim = 0; dim < Kohonen_Design.dimensions_of_signal; dim++) {Kohonen_Design.node_in_cluster_layer[knodes].input_value[dim] = Kohonen_Test[ktest].number_of_samples[pattern].data_in_sample[dim];} } Kohonen_Design.kluster_nodes_compete_for_activation(); Kohonen_savefile_ptr << pattern + 1 << " "; for(dim = 0; dim < Kohonen_Design.dimensions_of_signal; dim++) { realvalue = (Kohonen_Test[ktest].number_of_samples[pattern].data_in_sample[dim]*(Kohonen_Test[ktest].max_output_value[dim] - Kohonen_Test[ktest].min_output_value[dim])) + Kohonen_Test[ktest].min_output_value[dim]; Kohonen_savefile_ptr << realvalue << " "; } Kohonen_savefile_ptr << " " << Kohonen_Design.kluster_champ + 1 << "\n"; } Kohonen_savefile_ptr.close(); Kohonen_Test[ktest].delete_signal_array(); } // end test loop } void NeuralK::network_training_testing(int TT) { int tt = TT; int menu_choice; clrscr(); cout << "\n\n\n\n"; cout << "**************** Operations Menu ****************" << "\n\n"; cout << " Please select one of the following options:" <<"\n\n"; cout << " 1. Train Kohonen network only " <<"\n\n"; cout << " 2. Test Kohonen network only " <<"\n\n"; cout << " 3. Train and Test Kohonen network" <<"\n\n"; cout << "*************************************************" << "\n\n"; cout << " Your choice?: "; cin >> menu_choice; cout << "\n\n"; switch(menu_choice) { case 1: initialize_Kohonen_training_storage_array(tt); train_Kohonen_network(tt); break; case 2: establish_Kohonen_test_battery_size(); if(number_of_Kohonen_tests > 0) {test_Kohonen_network(tt);} break; case 3: initialize_Kohonen_training_storage_array(tt); train_Kohonen_network(tt); establish_Kohonen_test_battery_size(); if(number_of_Kohonen_tests > 0) {test_Kohonen_network(tt);} break; default:network_training_testing(tt); } } // This concludes the Kohonen section of the program //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // (Radial Basis Function Network) // define class and member functions which define Radial Basis Topology class Radial_Basis_Topology: public Kohonen_Topology { public: int number_of_output_units; Output_units *node_in_output_layer; int activation_function; void establish_Radial_Basis_topology(void); void establish_activation_function(void); void calculate_transfer_function_widths(void); void transfer_Gaussian_to_Output_layer(void); void upload_network(void); // retrieve network from file void savenet(void); ~Radial_Basis_Topology(); }; Radial_Basis_Topology::~Radial_Basis_Topology() { delete [] node_in_output_layer;} void Radial_Basis_Topology::establish_activation_function(void) { int dolock = 1; int bchoice; cout << "\n"; cout << "For the output layer:" << "\n"; do { cout << "please select the type of activation function you wish the nodes to use" << "\n\n"; cout << "1. Binary Sigmoid Function " << "\n"; cout << "2. Bipolar Sigmoid Function " << "\n\n"; cout << "Your Selection "; cin >> bchoice; cout << "\n\n"; if((bchoice == 1) || (bchoice == 2)) {dolock = 0;} } while(dolock >= 1); activation_function = bchoice; } void Radial_Basis_Topology::establish_Radial_Basis_topology(void) { char netcreate; int looploc = 0; do { cout <<"\n"; cout << "Do you wish to" << "\n\n"; cout << "C. Create your own RBF Network " << "\n"; cout << "U. Upload an existing RBF Network " << "\n\n"; cout << "Your choice?: "; cin >> netcreate; cout << "\n\n"; netcreate = toupper(netcreate); if((netcreate == 'C') || (netcreate == 'U')) {looploc = 1;} } while(looploc <= 0); if(netcreate == 'U') {upload_network();} else { cout << "Please enter the dimensions of the RBF networks's input signal vector: "; cin >> dimensions_of_signal; cout << "\n"; establish_Kohonen_topology(2); // establishes maximum number of clusters cout << "\n"; cout << "please enter the number of nodes in the RBF output layer: "; cin >> number_of_output_units; cout << "\n\n"; node_in_output_layer = new Output_units[number_of_output_units]; for(int o = 0; o < number_of_output_units; o++) { node_in_output_layer[o].number_of_input_units = maximum_number_of_clusters; node_in_output_layer[o].establish_array_of_processing_unit_inputs(); node_in_output_layer[o].establish_weight_vector_for_processing_units(); node_in_output_layer[o].bias = 1.0 - (2.0 * bedlam((long*)(gaset))); } establish_activation_function(); } } void Radial_Basis_Topology::upload_network(void) { char getname[13]; ifstream get_ptr; int netid, node, dim; int dolock = 0; do { cout << "\n\n"; cout << "Please enter the name of the file which holds the RBF network" << "\n"; cin >> getname; cout << "\n"; get_ptr.open(getname, ios::in); get_ptr >> netid; if(netid == 4) {dolock = 1;} else { cout << "Error** file contents do not match RBF specifications" << "\n"; cout << "try again" << "\n"; get_ptr.close(); } } while(dolock <= 0); get_ptr >> dimensions_of_signal; get_ptr >> number_of_output_units; get_ptr >> activation_function; get_ptr >> maximum_number_of_clusters; node_in_output_layer = new Output_units[number_of_output_units]; for(node = 0; node < number_of_output_units; node++) { node_in_output_layer[node].number_of_input_units = maximum_number_of_clusters; node_in_output_layer[node].establish_array_of_processing_unit_inputs(); node_in_output_layer[node].establish_weight_vector_for_processing_units(); get_ptr >> node_in_output_layer[node].bias; } for(node = 0; node < number_of_output_units; node++) { for(dim = 0; dim < maximum_number_of_clusters; dim++) {get_ptr >> node_in_output_layer[node].weight_of_inputs[dim];} } node_in_cluster_layer = new Kohonen_units[maximum_number_of_clusters]; for(node = 0; node < maximum_number_of_clusters; node++) { node_in_cluster_layer[node].number_of_inputs = dimensions_of_signal; node_in_cluster_layer[node].establish_input_output_arrays(); node_in_cluster_layer[node].establish_input_weight_vector_array(); get_ptr >> node_in_cluster_layer[node].transfer_function_width; } for(node = 0; node < maximum_number_of_clusters; node++) { for(dim = 0; dim < maximum_number_of_clusters; dim++) {get_ptr >> node_in_cluster_layer[node].input_weight_vector[dim];} } get_ptr.close(); } void Radial_Basis_Topology::calculate_transfer_function_widths(void) { float sum, w1, w2; int i, j, k, ihold, jhold, khold; for(i = 0; i < maximum_number_of_clusters; i++) {node_in_cluster_layer[i].transfer_function_width = 0.0;} for(i = 0; i < maximum_number_of_clusters - 1; i++) { for(j = i + 1; j < maximum_number_of_clusters; j++) { sum = 0.0; for(k = 0; k < dimensions_of_signal; k++) { khold = k; ihold = i; jhold = j; w1 = node_in_cluster_layer[ihold].input_weight_vector[khold]; w2 = node_in_cluster_layer[jhold].input_weight_vector[khold]; sum = pow((w1 - w2), 2.0); node_in_cluster_layer[ihold].transfer_function_width += sum; node_in_cluster_layer[jhold].transfer_function_width += sum; } } } for(i = 0; i < maximum_number_of_clusters; i++) { node_in_cluster_layer[i].transfer_function_width = (1.0 / (maximum_number_of_clusters - 1)) * node_in_cluster_layer[i].transfer_function_width; node_in_cluster_layer[i].transfer_function_width = pow(node_in_cluster_layer[i].transfer_function_width, 0.5); } } void Radial_Basis_Topology::transfer_Gaussian_to_Output_layer(void) { int i, j; for(i = 0; i < maximum_number_of_clusters; i++) { node_in_cluster_layer[i].calculate_sum_square_Euclidean_distance(); node_in_cluster_layer[i].execute_Gaussian_transfer_function(); } // transfer signal from cluster to output units and calculate output for(i = 0; i < number_of_output_units; i++) { for(j = 0; j < maximum_number_of_clusters; j++) {node_in_output_layer[i].processing_unit_input[j] = node_in_cluster_layer[j].Gaussian_transfer_output;} node_in_output_layer[i].calculate_output_signal(activation_function); } } void Radial_Basis_Topology::savenet(void) { char savename[13]; ofstream save_ptr; int node, dim; cout << "\n\n"; cout << "Please enter the name of the file which will hold the RBF network"<<"\n"; cin >> savename; cout <<"\n"; save_ptr.open(savename, ios::out); save_ptr << 4 << "\n"; //network identifier number save_ptr << dimensions_of_signal << "\n"; save_ptr << number_of_output_units << "\n"; save_ptr << activation_function << "\n"; save_ptr << maximum_number_of_clusters << "\n"; for(node = 0; node < number_of_output_units; node++) {save_ptr << node_in_output_layer[node].bias << " ";} save_ptr << "\n"; for(node = 0; node < number_of_output_units; node++) { for(dim = 0; dim < maximum_number_of_clusters; dim++) {save_ptr << node_in_output_layer[node].weight_of_inputs[dim] << " ";} save_ptr << "\n"; } for(node = 0; node < maximum_number_of_clusters; node++) {save_ptr << node_in_cluster_layer[node].transfer_function_width << " ";} save_ptr << "\n"; for(node = 0; node < maximum_number_of_clusters; node++) { for(dim = 0; dim < dimensions_of_signal; dim++) {save_ptr << node_in_cluster_layer[node].input_weight_vector[dim] << " ";} save_ptr << "\n"; } save_ptr.close(); } //****************************************************************************** class NeuralR // class containing the Radial Basis neural net structure { // along with training and testing data private: Training RTrain; // file name and dynamic array for training Testing *RTests; // files containing data to test network int number_of_tests; // number of tests run on the neural net void initialize_training_storage_array(int R); void establish_test_battery_size(void); void train_RBF_neural_network(int RBF); void test_neural_network(int RBN); public: Radial_Basis_Topology RBF_Design; // specification of radial basis network void establish_Radial_Basis_network(void); void network_training_testing(int TT); ~NeuralR(); }; //****************************************************************************** NeuralR::~NeuralR() {delete [] RTests;} void NeuralR::initialize_training_storage_array(int R) { RTrain.acquire_net_info(RBF_Design.dimensions_of_signal, RBF_Design.number_of_output_units); RTrain.request_training_data(R); } void NeuralR::establish_test_battery_size(void) { clrscr(); cout << "Please enter the number of tests you wish to run on the RBF network: "; cin >> number_of_tests; cout << "\n"; RTests = new Testing[number_of_tests]; for(int i = 0; i < number_of_tests; i++) {RTests[i].acquire_net_info(RBF_Design.dimensions_of_signal, RBF_Design.number_of_output_units);} } void NeuralR::establish_Radial_Basis_network(void) { clrscr(); cout << " **** Radial Basis Function Network **** " << "\n\n\n"; RBF_Design.establish_Radial_Basis_topology(); } void NeuralR::train_RBF_neural_network(int RBF) { char savefile; float output_error, sum_of_error, real_error_difference, target_minimum_average_squared_error; int bepoch, outnode, sig, sigdim, cnode; int dim, ep, k_epochs, pattern, knodes, dolock; float *maxdifference; float *meandifference; int loopexit = 1; ofstream savefile_ptr; // establish cluster centers weight vectors via K-means clustering clrscr(); cout <<"\n\n"; cout << "For Neural Network #"<> RBF_Design.max_learning_rate; cout <<"\n"; cout << "please enter the minimum learning rate parameter (0-1): "; cin >> RBF_Design.min_learning_rate; cout <<"\n"; cout << "please enter the number of epochs used to train the RBF clusters: "; cin >> k_epochs; cout << "\n\n\n"; ep = 0; dolock = 0; do { for(pattern = 0; pattern < RTrain.sample_number; pattern++) { for(knodes = 0; knodes < RBF_Design.maximum_number_of_clusters; knodes++) { for(dim = 0; dim < RBF_Design.dimensions_of_signal; dim++) { RBF_Design.node_in_cluster_layer[knodes].input_value[dim] = RTrain.number_of_samples[pattern].data_in_sample[dim]; } } RBF_Design.kluster_nodes_compete_for_activation(); RBF_Design.update_the_Kohonen_network(ep, k_epochs); } if((ep == k_epochs - 1) || (RBF_Design.interim_learning_rate == 0.0)) {dolock = 1;} ep = ep + 1; } while(dolock <= 0); RBF_Design.calculate_transfer_function_widths(); // use supervised learning for output layer weight vector cout << "Cluster center vectors established" << "\n\n"; cout << "please enter the number of epochs you wish to use for training"<< "\n"; cout << "the output layer: "; cin >> RTrain.number_of_epochs; cout<< "\n\n"; cout << "please enter the learning rate constant for backpropagation (0-1): "; cin >> RTrain.rate_of_learning; cout << "\n"; cout << "please enter the minimum average squared error you wish to target" << "\n"; cin >> target_minimum_average_squared_error; cout << "\n"; do { cout << "do you wish to save the mean error, maximum error" << "\n"; cout << "and average squared error for each epoch to a file? (Y or N): "; cin >> savefile; savefile = toupper(savefile); if((savefile == 'Y') || (savefile == 'N')) {loopexit = 2;} cout << "\n"; } while(loopexit <= 1); if(savefile == 'Y') { cout << "please enter the name of the file which will hold the results of training:" << "\n"; cin >> RTrain.resultsname; cout <<"\n"; savefile_ptr.open(RTrain.resultsname, ios::out); } maxdifference = new float[RBF_Design.number_of_output_units]; meandifference = new float[RBF_Design.number_of_output_units]; // intiate backpropagation for appropriate number of epochs bepoch = 0; do { sum_of_error = 0; for(sig = 0; sig < RTrain.sample_number; sig++) { output_error = 0; for(sigdim = 0; sigdim < RTrain.signal_dimensions; sigdim++) { for(cnode = 0; cnode < RBF_Design.maximum_number_of_clusters; cnode++) {RBF_Design.node_in_cluster_layer[cnode].input_value[sigdim] = RTrain.number_of_samples[sig].data_in_sample[sigdim];} } RBF_Design.transfer_Gaussian_to_Output_layer(); for(outnode = 0; outnode < RBF_Design.number_of_output_units; outnode++) { RBF_Design.node_in_output_layer[outnode].calculate_output_error_information_term(RTrain.number_of_samples[sig].data_in_sample[RTrain.signal_dimensions + outnode], RBF_Design.activation_function); // calculate the instantaneous sum of squared errors (Haykin, 1994) real_error_difference = (pow(RBF_Design.node_in_output_layer[outnode].error_difference_squared, 0.5)) * (RTrain.max_output_value[outnode] - RTrain.min_output_value[outnode]); output_error += 0.5 * pow(real_error_difference, 2.0); // calculate maximum and mean absolute error difference for each node real_error_difference = RBF_Design.node_in_output_layer[outnode].absolute_error_difference * (RTrain.max_output_value[outnode] - RTrain.min_output_value[outnode]); meandifference[outnode] += real_error_difference / float(RTrain.sample_number); if(sig == 0) {maxdifference[outnode] = real_error_difference;} else { if(real_error_difference > maxdifference[outnode]) {maxdifference[outnode] = real_error_difference;} } } // average squared error for each signal is saved sum_of_error += output_error / float (RTrain.sample_number); // update the RBF network's output nodes for(outnode = 0; outnode < RBF_Design.number_of_output_units; outnode++) {RBF_Design.node_in_output_layer[outnode].calculate_weight_and_bias_correction_terms(RTrain.rate_of_learning);} } // end sig loop // save error information (if required) if(savefile == 'Y') { savefile_ptr << bepoch + 1 << " "; savefile_ptr << sum_of_error << " "; for(outnode = 0; outnode < RBF_Design.number_of_output_units; outnode++) {savefile_ptr << maxdifference[outnode] << " " << meandifference[outnode] << " ";} savefile_ptr << endl; cout.width(6); clrscr(); cout << "Epoch #"<< bepoch + 1 <<" is completed " << endl; } if(bepoch == 0) {RTrain.minimum_average_squared_error = sum_of_error;} else { if(sum_of_error < RTrain.minimum_average_squared_error) {RTrain.minimum_average_squared_error = sum_of_error;} } for(outnode = 0; outnode < RBF_Design.number_of_output_units; outnode++) { maxdifference[outnode] = 0.0; meandifference[outnode] = 0.0;} if(RTrain.minimum_average_squared_error <= target_minimum_average_squared_error) {break;} bepoch = bepoch + 1; } while(bepoch < RTrain.number_of_epochs); savefile_ptr.close(); // delete arrays holding the training data RTrain.delete_signal_data_array(); delete [] maxdifference; delete [] meandifference; } void NeuralR::test_neural_network(int RBN) { float output_error, real_output; int sig, sigdim, knodes, outnode; int rbn = RBN; for(int RBtest = 0; RBtest < number_of_tests; RBtest++) { RTests[RBtest].request_testing_data(rbn, RBtest + 1); cout << "please enter the name of the file which will hold the results of test: " << RBtest + 1 << "\n"; cin >> RTests[RBtest].resultsname; cout << "\n"; ofstream savefile_ptr(RTests[RBtest].resultsname); for(sig = 0; sig < RTests[RBtest].sample_number; sig++) { output_error = 0.0; savefile_ptr << sig + 1 <<" "; for(knodes = 0; knodes < RBF_Design.maximum_number_of_clusters; knodes++) { for(sigdim = 0; sigdim < RBF_Design.dimensions_of_signal; sigdim++) {RBF_Design.node_in_cluster_layer[knodes].input_value[sigdim] = RTests[RBtest].number_of_samples[sig].data_in_sample[sigdim];} } RBF_Design.transfer_Gaussian_to_Output_layer(); // send target output to a file for(outnode = 0; outnode < RBF_Design.number_of_output_units; outnode++) { real_output = RTests[RBtest].min_output_value[outnode] + (RTests[RBtest].number_of_samples[sig].data_in_sample[outnode + RBF_Design.dimensions_of_signal] * (RTests[RBtest].max_output_value[outnode] - RTests[RBtest].min_output_value[outnode])); savefile_ptr << real_output << " "; } savefile_ptr <<" "; // send network output to a file for(outnode = 0; outnode < RBF_Design.number_of_output_units; outnode++) { RBF_Design.node_in_output_layer[outnode].calculate_output_error_information_term(RTests[RBtest].number_of_samples[sig].data_in_sample[RTests[RBtest].signal_dimensions + outnode], RBF_Design.activation_function); real_output = RTests[RBtest].min_output_value[outnode] + (RBF_Design.node_in_output_layer[outnode].output_signal * (RTests[RBtest].max_output_value[outnode] - RTests[RBtest].min_output_value[outnode])); savefile_ptr << real_output << " "; } // send absolute error difference to a file for(outnode = 0; outnode < RBF_Design.number_of_output_units; outnode++) { real_output = (pow(RBF_Design.node_in_output_layer[outnode].error_difference_squared, 0.5)) * (RTests[RBtest].max_output_value[outnode] - RTests[RBtest].min_output_value[outnode]); savefile_ptr << real_output << " "; real_output = pow(real_output, 2.0); output_error += 0.5 * real_output; } // save sum square of error savefile_ptr << output_error << "\n"; if(sig == RTests[RBtest].sample_number - 1) {savefile_ptr.close();} } RTests[RBtest].delete_signal_array(); } } // end test neural network function void NeuralR::network_training_testing(int TT) { int tt = TT; int menu_choice; clrscr(); cout << "\n\n\n\n"; cout << "**************** Operations Menu ****************" << "\n\n"; cout << " Please select one of the following options:" <<"\n\n"; cout << " 1. Train RBF network only " <<"\n\n"; cout << " 2. Test RBF network only " <<"\n\n"; cout << " 3. Train and Test RBF network" <<"\n\n"; cout << "*************************************************" << "\n\n"; cout << " Your choice?: "; cin >> menu_choice; cout << "\n\n"; switch(menu_choice) { case 1: initialize_training_storage_array(tt); train_RBF_neural_network(tt); break; case 2: establish_test_battery_size(); if(number_of_tests > 0) {test_neural_network(tt);} break; case 3: initialize_training_storage_array(tt); train_RBF_neural_network(tt); establish_test_battery_size(); if(number_of_tests > 0) {test_neural_network(tt);} break; default:network_training_testing(tt); } } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // this template class stores the neural networks to a file template class Storage { public: void save_neural_network(Type & NET_Topology); }; template void Storage::save_neural_network(Type & NET_Topology) { char schoice; int dolock = 0; do { clrscr(); cout << "\n\n\n\n"; cout << "Do you wish to save this neural network? (Y/N): "; cin >> schoice; schoice = toupper(schoice); if((schoice == 'Y') || (schoice == 'N')) {dolock = 1;} } while(dolock <= 0); if(schoice == 'Y') {NET_Topology.savenet();} } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% class Neural_Window // this class holds the different types of neural nets { private: void establish_network_type(void); public: // user interface char neural_network_type; int neural_network_number; void display_menu_for_net_selection(int NNnum); }; void Neural_Window::display_menu_for_net_selection(int NNnum) { clrscr(); neural_network_number = NNnum; cout.fill('*'); cout.width(70); cout << "\n"; cout.width(42); cout << " Neural Network " << neural_network_number << " "; cout.width(26); cout << "\n"; cout.width(71); cout << "\n\n"; cout << "Please select one of the following network types from the Main Menu"; int i = 0; do {cout << "\n"; i = i + 1;} while (i < 3); cout.fill(' '); cout.width(10); cout << " *** / Main Menu \\ ***"; cout << "\n\n"; cout.width(6); cout << " F. Feedforward network using backpropagation " << "\n\n"; cout.width(6); cout << " A. Adaptive Resonance Theory network for binary signals " <<"\n\n"; cout.width(6); cout << " K. Kohonen Self-Organizing Map " <<"\n\n"; cout.width(6); cout << " R. Radial Basis Function Network " <<"\n\n"; cout.width(6); cout << " E. Exit Program" <<"\n\n"; cout << "\n\n\n"; cout.width(6); cout << "Network Type (?) "; cin >> neural_network_type; neural_network_type = toupper(neural_network_type); if(neural_network_type != 'E') {establish_network_type();} } void Neural_Window::establish_network_type(void) { int NNN = neural_network_number; NeuralA *ART; NeuralB *Backpropagation; NeuralK *KOH; NeuralR *RBF; switch(neural_network_type) { case 'A': // Adaptive Resonance Theory Network (ART1) for clustering ART = new NeuralA; Storage Astore; ART->construct_ART_network(); ART->network_training_testing(NNN); Astore.save_neural_network(ART->ART_Design); break; case 'F': // Feedforward Network Using Backpropagation Backpropagation = new NeuralB; Storage Bstore; Backpropagation->establish_backprop_network(); Backpropagation->network_training_testing(NNN); Bstore.save_neural_network(Backpropagation->Net_Design); break; case 'K': // Kohonen Self-Organizing Map KOH = new NeuralK; Storage Kstore; KOH->construct_Kohonen_network(); KOH->network_training_testing(NNN); Kstore.save_neural_network(KOH->Kohonen_Design); break; case 'R': // Radial Basis Function Network RBF = new NeuralR; Storage Rstore; RBF->establish_Radial_Basis_network(); RBF->network_training_testing(NNN); Rstore.save_neural_network(RBF->RBF_Design); break; default: display_menu_for_net_selection(neural_network_number); } } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void main(void) { _control87(MCW_EM, MCW_EM); // will mask floating point overflows, // underflows, or divisions by 0 int number_of_nets; Neural_Window User_net; clrscr(); cout << " ******* Welcome to Pitt-Networks!! ******** " << "\n\n\n\a"; cout << "Please enter the number of networks you wish to develop: "; cin >> number_of_nets; for(int NWnet = 1; NWnet < number_of_nets + 1; NWnet++) { User_net.display_menu_for_net_selection(NWnet); if(User_net.neural_network_type == 'E') {break;} } }