风花雪月 发表于 2006-10-12 09:59

神经网络基本算法源程序

神经网络基本算法源程序,包含四个基本算法:BF,ART I,RBF,自组织算法

Pittnet currently has four popular neural network paradigms:
(1) backpropagation (BP)
(2) Kohonen self-organizing
(3) adaptive resonance theory I (ART I)
(4) radial basis function (RBF).
Pittnet takes ascii text files as inputs and the output files are also ascii text.
Pittnet is designed to run on any hardware including low end PC's. The source may
be modified by the students to customize the neural networks or to include the neural
networks as components of larger software systems. The cascade correlation network
paradigm will be added to Pittnet in the near future. The developement of Pittnet was
funded by the National Science Foundation (NSF) grant, CAREER, DMI 9502134.

// 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 <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <iostream.h>
#include <string.h>
#include <conio.h>
#include <float.h>
#include <fstream.h>
#include <ctype.h>

#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 EPS1.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;
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 = *idum;
      }
    }
      iy = iv;
}

xk = (*idum) / IQ;
*idum = IA * (*idum - xk * IQ) - IR * xk;
if(*idum < 0)
{
    *idum += IM;
}
xj = iy / NDIV;
iy = iv;
iv = *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;
weight_of_inputs = new float;
weight_correction_term = new float;
}

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 = 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 * weight_of_inputs) + bias;}
   else
   {sum_of_weighted_inputs += processing_unit_input * weight_of_inputs;}
}

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 = learning_rate * error_information_term * processing_unit_input;}
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 = weight_of_inputs + weight_correction_term;}
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;
   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.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.nodes_in_hidden_layer;
        hidden_layer_number.node_in_hidden_layer = new Hidden_units;
      }
    }
    node_in_output_layer = new Output_units;

    if(number_of_hidden_layers > 0)
    {
      // establish input connection between signal and hidden layer
      for(nodes = 0; nodes < hidden_layer_number.nodes_in_hidden_layer; nodes++)
      {
        hidden_layer_number.node_in_hidden_layer.number_of_input_units = signal_dimensions;
        hidden_layer_number.node_in_hidden_layer.establish_array_of_processing_unit_inputs();
        hidden_layer_number.node_in_hidden_layer.establish_weight_vector_for_processing_units();
        hidden_layer_number.node_in_hidden_layer.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.nodes_in_hidden_layer; nodes++)
        {
          hidden_layer_number.node_in_hidden_layer.number_of_input_units = hidden_layer_number.nodes_in_hidden_layer;
          hidden_layer_number.node_in_hidden_layer.establish_array_of_processing_unit_inputs();
          hidden_layer_number.node_in_hidden_layer.establish_weight_vector_for_processing_units();
          hidden_layer_number.node_in_hidden_layer.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.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.number_of_input_units = inputs_to_output_node;
   node_in_output_layer.establish_array_of_processing_unit_inputs();
   node_in_output_layer.establish_weight_vector_for_processing_units();
   node_in_output_layer.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;
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;
for(nodes = 0; nodes < nodes_in_output_layer; nodes++)
{
   node_in_output_layer.number_of_input_units = inputs_to_output_node;
   node_in_output_layer.establish_array_of_processing_unit_inputs();
   node_in_output_layer.establish_weight_vector_for_processing_units();
   get_ptr >> node_in_output_layer.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.weight_of_inputs;}
}

// establish hidden layer(s)
get_ptr >> number_of_hidden_layers;
if(number_of_hidden_layers > 0)
{
    hidden_layer_number = new Hidden_layer;
    get_ptr >> activation_function_for_hidden_layer;
    for(hid = 0; hid < number_of_hidden_layers; hid++)
    {
      get_ptr >> hidden_layer_number.nodes_in_hidden_layer;
      nodes = hidden_layer_number.nodes_in_hidden_layer;
      hidden_layer_number.node_in_hidden_layer = new Hidden_units;

      if(hid == 0) {inputs = signal_dimensions;}
      else
      {inputs = hidden_layer_number.nodes_in_hidden_layer;}

      for(nodes = 0; nodes < hidden_layer_number.nodes_in_hidden_layer; nodes++)
      {
        hidden_layer_number.node_in_hidden_layer.number_of_input_units = inputs;
        hidden_layer_number.node_in_hidden_layer.establish_array_of_processing_unit_inputs();
        get_ptr >> hidden_layer_number.node_in_hidden_layer.bias;
      }
      for(nodes = 0; nodes < hidden_layer_number.nodes_in_hidden_layer; nodes++)
      {
        for(dim = 0; dim < inputs; dim++)
        {get_ptr >> hidden_layer_number.node_in_hidden_layer.weight_of_inputs;}
      }
    }
}
get_ptr.close();
}

void Back_Topology::savenet(void)
{
char savename;
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.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.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.weight_of_inputs << " ";}
    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.nodes_in_hidden_layer << "\n";
      if(hid == 0) {inputs = signal_dimensions;}
      else {inputs = hidden_layer_number.nodes_in_hidden_layer;}

      for(nodes = 0; nodes < hidden_layer_number.nodes_in_hidden_layer; nodes++)
      {save_ptr << hidden_layer_number.node_in_hidden_layer.bias << " ";}
      save_ptr << "\n";

      for(nodes = 0; nodes < hidden_layer_number.nodes_in_hidden_layer; nodes++)
      {
        for(dim = 0; dim < inputs; dim++)
        {save_ptr << hidden_layer_number.node_in_hidden_layer.weight_of_inputs << " ";}
        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;                     // File containing data for network training or testing
char resultsname;                  // 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;
min_output_value = new float;

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.data_in_sample;
        min = number_of_samples.data_in_sample;
        if((j >= (total_dimension - nodes_in_output_layer)))
        {
          min_output_value = min;
          max_output_value = max;
        }
      }
      else
      {
        if(number_of_samples.data_in_sample < min)
        {
          min = number_of_samples.data_in_sample;
          if(j >= (total_dimension - nodes_in_output_layer))
          {min_output_value = min;}
        }

        if(number_of_samples.data_in_sample > max)
        {
          max = number_of_samples.data_in_sample;
          if(j >= (total_dimension - nodes_in_output_layer))
          {max_output_value = max;}
        }
      }
    }

    imax = int(max_output_value);
    imin = int(min_output_value);
    rmax = max_output_value;
    rmin = min_output_value;

      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.data_in_sample = (number_of_samples.data_in_sample - 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;

for(i = 0; i < sample_number; i++)
// create a dynamic array to hold the dimensions of each signal
{number_of_samples.data_in_sample = new float;}

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.data_in_sample;}
}
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;
for(int i = 0; i < sample_number; i++) {signalpoint.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.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.signal_rank > signalpoint.signal_rank)
      {
        hold_sample = signalpoint.signal_value;
        hold_rank = signalpoint.signal_rank;
        signalpoint.signal_value = signalpoint.signal_value;
        signalpoint.signal_rank = signalpoint.signal_rank;
        signalpoint.signal_value = hold_sample;
        signalpoint.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;
    for(int i = 0; i < number_of_tests; i++)
    {Test_Data.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;
   meandifference = new float;

   // 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.processing_unit_input = Training_Data.number_of_samples.signal_value].data_in_sample;}
       }
       else // 1 or 2 hidden layers present
       {
        for(hidnode = 0; hidnode < Net_Design.hidden_layer_number.nodes_in_hidden_layer; hidnode++)
        {Net_Design.hidden_layer_number.node_in_hidden_layer.processing_unit_input = Training_Data.number_of_samples.signal_value].data_in_sample;}
       }
      }

      if(Net_Design.number_of_hidden_layers == 2) // two layers are present
      {
        for(hidnode = 0; hidnode < Net_Design.hidden_layer_number.nodes_in_hidden_layer; hidnode++)
        {
          Net_Design.hidden_layer_number.node_in_hidden_layer.calculate_output_signal(Net_Design.activation_function_for_hidden_layer);
          for(hidnode2 = 0; hidnode2 < Net_Design.hidden_layer_number.nodes_in_hidden_layer; hidnode2++)
          {Net_Design.hidden_layer_number.node_in_hidden_layer.processing_unit_input = Net_Design.hidden_layer_number.node_in_hidden_layer.output_signal;}
        }
      }

      if(Net_Design.number_of_hidden_layers > 0)
      {
        for(hidnode = 0; hidnode < Net_Design.hidden_layer_number.nodes_in_hidden_layer; hidnode++)
        {
          Net_Design.hidden_layer_number.node_in_hidden_layer.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.processing_unit_input = Net_Design.hidden_layer_number.node_in_hidden_layer.output_signal;}
        }
      }
      for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++)
      {
        Net_Design.node_in_output_layer.calculate_output_signal(Net_Design.activation_function_for_output_layer);
        Net_Design.node_in_output_layer.calculate_output_error_information_term(Training_Data.number_of_samples.signal_value].data_in_sample, 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.error_difference_squared, 0.5)) * (Training_Data.max_output_value - Training_Data.min_output_value);
        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.absolute_error_difference * (Training_Data.max_output_value - Training_Data.min_output_value);
        meandifference += real_error_difference / float(Training_Data.sample_number);
        if(sig == 0) {maxdifference = real_error_difference;}
        else
        {
          if(real_error_difference > maxdifference)
          {maxdifference = 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.nodes_in_hidden_layer; hidnode++)
          {Net_Design.hidden_layer_number.node_in_hidden_layer.error_information_term += Net_Design.node_in_output_layer.error_information_term * Net_Design.node_in_output_layer.weight_of_inputs;}
        }
        // calculate error information term for each node in hiddenlayer
        for(hidnode = 0; hidnode < Net_Design.hidden_layer_number.nodes_in_hidden_layer; hidnode++)
        {Net_Design.hidden_layer_number.node_in_hidden_layer.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.nodes_in_hidden_layer; hidnode2++)
          {
              for(hidnode = 0; hidnode < Net_Design.hidden_layer_number.nodes_in_hidden_layer; hidnode++)
              {Net_Design.hidden_layer_number.node_in_hidden_layer.error_information_term += Net_Design.hidden_layer_number.node_in_hidden_layer.error_information_term * Net_Design.hidden_layer_number.node_in_hidden_layer.weight_of_inputs;}
          }
          for(hidnode = 0; hidnode < Net_Design.hidden_layer_number.nodes_in_hidden_layer; hidnode++)
          {Net_Design.hidden_layer_number.node_in_hidden_layer.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.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.nodes_in_hidden_layer; hidnode++)
          {Net_Design.hidden_layer_number.node_in_hidden_layer.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 << " " << meandifference << "    ";}
        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 = 0.0; meandifference = 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.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.resultsname; cout <<"\n";
      ofstream savefile_ptr(Test_Data.resultsname);

    for(sig = 0; sig < Test_Data.sample_number; sig++)
    {
      output_error = 0;
      savefile_ptr << sig + 1 << " ";

      for(sigdim = 0; sigdim < Test_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.processing_unit_input = Test_Data.number_of_samples.data_in_sample;}
       }
       else // 1 or 2 hidden layers present
       {
        for(hidnode = 0; hidnode < Net_Design.hidden_layer_number.nodes_in_hidden_layer; hidnode++)
        {Net_Design.hidden_layer_number.node_in_hidden_layer.processing_unit_input = Test_Data.number_of_samples.data_in_sample;}
       }
      }

      if(Net_Design.number_of_hidden_layers == 2) // two layers are present
      {
        for(hidnode = 0; hidnode < Net_Design.hidden_layer_number.nodes_in_hidden_layer; hidnode++)
        {
          Net_Design.hidden_layer_number.node_in_hidden_layer.calculate_output_signal(Net_Design.activation_function_for_hidden_layer);
          for(hidnode2 = 0; hidnode2 < Net_Design.hidden_layer_number.nodes_in_hidden_layer; hidnode2++)
          {Net_Design.hidden_layer_number.node_in_hidden_layer.processing_unit_input = Net_Design.hidden_layer_number.node_in_hidden_layer.output_signal;}
        }
      }

      if(Net_Design.number_of_hidden_layers > 0)
      {
        for(hidnode = 0; hidnode < Net_Design.hidden_layer_number.nodes_in_hidden_layer; hidnode++)
        {
          Net_Design.hidden_layer_number.node_in_hidden_layer.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.processing_unit_input = Net_Design.hidden_layer_number.node_in_hidden_layer.output_signal;}
        }
      }
      for(outnode = 0; outnode < Net_Design.nodes_in_output_layer; outnode++)
      {
        Net_Design.node_in_output_layer.calculate_output_signal(Net_Design.activation_function_for_output_layer);
        Net_Design.node_in_output_layer.calculate_output_error_information_term(Test_Data.number_of_samples.data_in_sample.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.min_output_value + (Test_Data.number_of_samples.data_in_sample.signal_dimensions] * (Test_Data.max_output_value - Test_Data.min_output_value));
             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.min_output_value + (Net_Design.node_in_output_layer.output_signal * (Test_Data.max_output_value - Test_Data.min_output_value));
             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.error_difference_squared, 0.5)) * (Test_Data.max_output_value - Test_Data.min_output_value);
        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.sample_number - 1)
        {savefile_ptr.close();}

        sum_of_error += output_error;
    }
        Test_Data.average_squared_error = sum_of_error / Test_Data.sample_number;
        Test_Data.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;
output_value = new float;
}

void ART_units::establish_input_weight_vector_array(void)
{input_weight_vector = new float;}

void ART_units::initialize_inputs_and_weights(void)
{
for(int w = 0; w < number_of_inputs - 1; w++)
{input_weight_vector = 1.0;}

for(int c = 1; c < number_of_inputs; c++)
{input_value = 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 * input_weight_vector;}

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*input_value;}

two_thirds_rule = feedback_signal + input_value + 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 = 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;}

void Cluster_units::initialize_inputs_and_weights(void)
{
for(int c = 0; c < number_of_inputs; c++)
{input_weight_vector = 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 * input_weight_vector;}
}

void Cluster_units::establish_node_output(void)
{
for(int oput = 0; oput < number_of_outputs - 1; oput++)
if(activation >= 0.0)
{output_value = activation;}
else
{output_value = 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;
node_in_interface_layer = new Interface_units;
node_in_cluster_layer = new Cluster_units;

// Establish interface layer of ART1 network
for(int I = 0; I < dimensions_of_signal; I++)
{
    node_in_interface_layer.number_of_inputs = number_of_cluster_units + 1;
    node_in_interface_layer.number_of_outputs = number_of_cluster_units;
    node_in_interface_layer.establish_input_output_arrays();
    node_in_interface_layer.establish_input_weight_vector_array();
    node_in_interface_layer.initialize_inputs_and_weights();
}

// Establish cluster layer of ART1 network
for(int C = 0; C < number_of_cluster_units; C++)
{
    node_in_cluster_layer.number_of_inputs = dimensions_of_signal;
    node_in_cluster_layer.number_of_outputs = dimensions_of_signal + 1;
    node_in_cluster_layer.establish_input_output_arrays();
    node_in_cluster_layer.establish_input_weight_vector_array();
    node_in_cluster_layer.initialize_inputs_and_weights();
}

}

void ART_Topology::upload_network(void)
{
char getname;
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;
node_in_interface_layer = new Interface_units;
node_in_cluster_layer = new Cluster_units;

for(node = 0; node < dimensions_of_signal; node++)
{
    node_in_interface_layer.number_of_inputs = number_of_cluster_units + 1;
    node_in_interface_layer.number_of_outputs = number_of_cluster_units;
    node_in_interface_layer.establish_input_output_arrays();
    node_in_interface_layer.establish_input_weight_vector_array();
    node_in_interface_layer.initialize_inputs_and_weights();
    for(dim = 1; dim < number_of_cluster_units + 1; dim++)
    {get_ptr >> node_in_interface_layer.input_weight_vector;}
}

for(node = 0; node < number_of_cluster_units; node++)
{
    node_in_cluster_layer.number_of_inputs = dimensions_of_signal;
    node_in_cluster_layer.number_of_outputs = dimensions_of_signal + 1;
    node_in_cluster_layer.establish_input_output_arrays();
    node_in_cluster_layer.establish_input_weight_vector_array();
    node_in_cluster_layer.initialize_inputs_and_weights();
    get_ptr >> node_in_cluster_layer.cluster_tag;
    for(dim = 0; dim < dimensions_of_signal; dim++)
    {get_ptr >> node_in_cluster_layer.input_weight_vector;}
}
get_ptr.close();
}

void ART_Topology::transmit_pattern_to_interface(void)
{
for(int d = 0; d < dimensions_of_signal; d++)
{
    node_in_interface_layer.input_value = node_in_input_layer.signal_value;
    node_in_interface_layer.activation = node_in_input_layer.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.input_value = node_in_input_layer.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.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.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.input_value = node_in_interface_layer.output_value;}
}
}

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.activation != -1.0)
    {
      node_in_cluster_layer.calculate_net_input();
      if(node_in_cluster_layer.net_input > champion)
      {
        champion = node_in_cluster_layer.net_input;
        cluster_champ = cluster;
      }
    }
}
    if((node_in_cluster_layer.cluster_tag == 0) && (train_or_test < 2))
    {
      node_in_cluster_layer.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.activation = 1.0;}
      else
      {
        if(node_in_cluster_layer.activation != -1.0)
        {node_in_cluster_layer.activation = 0.0;}
      }
      node_in_cluster_layer.establish_node_output();

      // send output signals to Interface layer
      for(d = 0; d < dimensions_of_signal; d++)
      {node_in_interface_layer.input_value = node_in_cluster_layer.output_value;}
    }
}
}

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.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.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.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.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.number_of_inputs; u++)
    {node_in_cluster_layer.input_weight_vector = (weight_update_parameter * node_in_interface_layer.activation * node_in_cluster_layer.input_weight_vector) / ((weight_update_parameter - 1.0) + norm_of_activation_vector);}
    for(int n = 0; n < dimensions_of_signal; n++)
    {node_in_interface_layer.input_weight_vector = node_in_interface_layer.input_weight_vector * node_in_interface_layer.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.activation = 0.0;}
}

void ART_Topology::savenet(void)
{
char savename;
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.input_weight_vector << " ";}
    save_ptr << "\n";
}

for(node = 0; node < number_of_cluster_units; node++)
{
    save_ptr << node_in_cluster_layer.cluster_tag << "\n";
    for(dim = 0; dim < dimensions_of_signal; dim++)
    {save_ptr << node_in_cluster_layer.input_weight_vector << " ";}
    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;

   for(i = 0; i < sample_number; i++)
   {number_of_samples.data_in_sample = new float;}

   // 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.data_in_sample = 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.signal_value = ART_Train.number_of_samples.data_in_sample;}

    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.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.signal_value);}
      ART_savefile_ptr << " " << ART_Design.node_in_cluster_layer.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;
    for(int t = 0; t < number_of_ART_tests; t++)
    {ART_Test.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.request_ART_data(tnet);
    cout << "For ART1 neural network #" << ANET <<" and test #"<<Atest+1<<":" <<"\n";
    cout << "please enter the name of the file to hold the results of the ART Testing " << "\n";
    cin>> ART_Test.resultsname; cout << "\n";
    ofstream ART_savefile_ptr(ART_Test.resultsname);

    for(pattern = 0; pattern < ART_Test.sample_number; pattern++)
    {
      for(dim = 0; dim < ART_Design.dimensions_of_signal; dim++)
      {ART_Design.node_in_input_layer.signal_value = ART_Test.number_of_samples.data_in_sample;}

      ART_Design.transmit_pattern_to_cluster();
      ART_Design.cluster_nodes_compete_for_activation(2);

      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.signal_value);}

      ART_savefile_ptr << " " << ART_Design.node_in_cluster_layer.cluster_tag << "\n";
    }

      ART_savefile_ptr.close();      // end of test
      ART_Test.delete_signal_array();
}

}

void NeuralA::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 ART1 network only " <<"\n\n";
if(ART_Design.netcreate == 'U')
{
    cout << "      2. Test ART1 network only " <<"\n\n";
    cout << "      3. Train and Test ART1 network" <<"\n\n";
}
else
{
    cout << "      2. Train and Test ART1 network" <<"\n\n";
}
cout << "*************************************************" << "\n\n";
cout << "         Your choice?: "; cin >> 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;}

void Kohonen_units::initialize_inputs_and_weights(void)
{
for(int k = 0; k < number_of_inputs; k++)
{input_weight_vector = bedlam((long*)(gaset));}
}

void Kohonen_units::calculate_sum_square_Euclidean_distance(void)
{
double sumsquare;
float ss1;
int ci;
output_value = 0.0;
for(int k = 0; k < number_of_inputs; k++)
{
    ci = k;

    if(input_value == 0.0)
    {
      sumsquare = pow(input_weight_vector, 2.0);
    }
    else
    {
      sumsquare = pow(fabs(input_weight_vector - input_value), 2.0);
    }
    output_value += sumsquare;
    // cout << output_value << "\n";
    // cin >> output_value;
}
ss1 = output_value;

output_value = sqrt(fabs(ss1));

}

void Kohonen_units::update_the_weights(float learning_rate)
{
for(int k = 0; k < number_of_inputs; k++)
{input_weight_vector = input_weight_vector + (learning_rate * (input_value - input_weight_vector));}
}
// RBFN //
void Kohonen_units::execute_Gaussian_transfer_function(void)
{
float transfer_ratio = (-1.0) * pow((output_value / 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;
   for(int c = 0; c < maximum_number_of_clusters; c++)
   {
   node_in_cluster_layer.number_of_inputs = dimensions_of_signal;
   node_in_cluster_layer.establish_input_output_arrays();
   node_in_cluster_layer.establish_input_weight_vector_array();
   node_in_cluster_layer.initialize_inputs_and_weights();
   }
}
}

void Kohonen_Topology::upload_network(void)
{
char getname;
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;
for(nodes = 0; nodes < maximum_number_of_clusters; nodes++)
{
   node_in_cluster_layer.number_of_inputs = dimensions_of_signal;
   node_in_cluster_layer.establish_input_output_arrays();
   node_in_cluster_layer.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.input_weight_vector;}
}
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.calculate_sum_square_Euclidean_distance();
    if(m == 0)
    {
      kluster_champ = m;
      minimum_distance = node_in_cluster_layer.output_value;
    }
    else
    {
      if(node_in_cluster_layer.output_value < minimum_distance)
      {
        kluster_champ = m;
        minimum_distance = node_in_cluster_layer.output_value;
      }
    }
}
}

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.update_the_weights(interim_learning_rate);
}

void Kohonen_Topology::savenet(void)
{
char savename;
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.input_weight_vector << " ";}
    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;
min_output_value = new float;

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.data_in_sample;
        min = number_of_samples.data_in_sample;
      }
      else
      {
        if(number_of_samples.data_in_sample < min)
        {min = number_of_samples.data_in_sample;}

        if(number_of_samples.data_in_sample > max)
        {max = number_of_samples.data_in_sample;}
      }
    }

    // normalize the values in each dimension of the signal
    max_output_value = max;
    min_output_value = 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.data_in_sample = (number_of_samples.data_in_sample - 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. " <<net_no << "\n";
cin >> 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. " <<net_no << "\n";
cin >> 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;
    for(int t = 0; t < number_of_Kohonen_tests; t++)
    {Kohonen_Test.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 #"<<KOHN<<"\n\n";
cout << "please enter the maximum learning rate parameter (0-1): ";
cin >> 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.input_value = Kohonen_Train.number_of_samples.data_in_sample;}
      }
      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.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.resultsname; cout <<"\n";
    ofstream Kohonen_savefile_ptr(Kohonen_Test.resultsname);

    for(pattern = 0; pattern < Kohonen_Test.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.input_value = Kohonen_Test.number_of_samples.data_in_sample;}
      }
      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.number_of_samples.data_in_sample*(Kohonen_Test.max_output_value - Kohonen_Test.min_output_value)) + Kohonen_Test.min_output_value;
        Kohonen_savefile_ptr << realvalue << " ";
      }
      Kohonen_savefile_ptr << " " << Kohonen_Design.kluster_champ + 1 << "\n";
    }
    Kohonen_savefile_ptr.close();
    Kohonen_Test.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;
    for(int o = 0; o < number_of_output_units; o++)
    {
      node_in_output_layer.number_of_input_units =maximum_number_of_clusters;
      node_in_output_layer.establish_array_of_processing_unit_inputs();
      node_in_output_layer.establish_weight_vector_for_processing_units();
      node_in_output_layer.bias = 1.0 - (2.0 * bedlam((long*)(gaset)));
    }
    establish_activation_function();
}
}

void Radial_Basis_Topology::upload_network(void)
{
char getname;
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;
for(node = 0; node < number_of_output_units; node++)
{
    node_in_output_layer.number_of_input_units =maximum_number_of_clusters;
    node_in_output_layer.establish_array_of_processing_unit_inputs();
    node_in_output_layer.establish_weight_vector_for_processing_units();
    get_ptr >> node_in_output_layer.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.weight_of_inputs;}
}

node_in_cluster_layer = new Kohonen_units;
for(node = 0; node < maximum_number_of_clusters; node++)
{
   node_in_cluster_layer.number_of_inputs = dimensions_of_signal;
   node_in_cluster_layer.establish_input_output_arrays();
   node_in_cluster_layer.establish_input_weight_vector_array();
   get_ptr >> node_in_cluster_layer.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.input_weight_vector;}
}
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.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.input_weight_vector;
       w2 = node_in_cluster_layer.input_weight_vector;
       sum = pow((w1 - w2), 2.0);
       node_in_cluster_layer.transfer_function_width += sum;
       node_in_cluster_layer.transfer_function_width += sum;
      }
    }
}

for(i = 0; i < maximum_number_of_clusters; i++)
{
    node_in_cluster_layer.transfer_function_width = (1.0 / (maximum_number_of_clusters - 1)) * node_in_cluster_layer.transfer_function_width;
    node_in_cluster_layer.transfer_function_width = pow(node_in_cluster_layer.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.calculate_sum_square_Euclidean_distance();
    node_in_cluster_layer.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.processing_unit_input = node_in_cluster_layer.Gaussian_transfer_output;}
    node_in_output_layer.calculate_output_signal(activation_function);
}
}

void Radial_Basis_Topology::savenet(void)
{
char savename;
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.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.weight_of_inputs << " ";}
    save_ptr << "\n";
}

for(node = 0; node < maximum_number_of_clusters; node++)
{save_ptr << node_in_cluster_layer.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.input_weight_vector << " ";}
    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;
for(int i = 0; i < number_of_tests; i++)
{RTests.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<<"\n\n";
cout << "please enter the maximum learning rate parameter (0-1): ";
cin >> 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.input_value = RTrain.number_of_samples.data_in_sample;
        }

      }
      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;
   meandifference = new float;

   // 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.input_value = RTrain.number_of_samples.data_in_sample;}
      }
        RBF_Design.transfer_Gaussian_to_Output_layer();

   for(outnode = 0; outnode < RBF_Design.number_of_output_units; outnode++)
   {
        RBF_Design.node_in_output_layer.calculate_output_error_information_term(RTrain.number_of_samples.data_in_sample, RBF_Design.activation_function);
        // calculate the instantaneous sum of squared errors (Haykin, 1994)
        real_error_difference = (pow(RBF_Design.node_in_output_layer.error_difference_squared, 0.5)) * (RTrain.max_output_value - RTrain.min_output_value);
        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.absolute_error_difference * (RTrain.max_output_value - RTrain.min_output_value);
        meandifference += real_error_difference / float(RTrain.sample_number);
        if(sig == 0) {maxdifference = real_error_difference;}
        else
        {
          if(real_error_difference > maxdifference)
          {maxdifference = 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.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 << " " << meandifference << "    ";}
        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 = 0.0; meandifference = 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.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.resultsname; cout << "\n";
   ofstream savefile_ptr(RTests.resultsname);

   for(sig = 0; sig < RTests.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.input_value = RTests.number_of_samples.data_in_sample;}
   }
   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.min_output_value + (RTests.number_of_samples.data_in_sample * (RTests.max_output_value - RTests.min_output_value));
       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.calculate_output_error_information_term(RTests.number_of_samples.data_in_sample.signal_dimensions + outnode], RBF_Design.activation_function);
       real_output = RTests.min_output_value + (RBF_Design.node_in_output_layer.output_signal * (RTests.max_output_value - RTests.min_output_value));
       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.error_difference_squared, 0.5)) * (RTests.max_output_value - RTests.min_output_value);
        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.sample_number - 1)
        {savefile_ptr.close();}
   }
        RTests.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 Type>
class Storage
{
public:
void save_neural_network(Type & NET_Topology);
};

template <class Type>
void Storage<Type>::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<ART_Topology> 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<Back_Topology> 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<Kohonen_Topology> 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<Radial_Basis_Topology> 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);

   }

}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

voidmain(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;}
}

}

风花雪月 发表于 2006-10-12 09:59

编译成功后的文件以及相关的帮助
http://www.pudn.com/downloads29/sourcecode/others/detail82080.html

本程序版权属原作者所有,此处仅提供欣赏,程序所有者如有异议请和本人联系删除

heiyanzi123 发表于 2007-10-10 10:00

楼主你好

楼主你好 你的这个程序我运行时怎么老是出现错误?你能不能把编译成功后的文件及相关的帮助 发到我的邮箱 heiyanzi123@126.com小弟非常感激!

shiqh 发表于 2008-7-7 10:09

楼主好,有没有matlab程序啊?

彩色沙漠之狮 发表于 2008-10-30 09:43

不错,谢谢啊,:loveliness:

huihuixy 发表于 2008-11-29 10:12

感谢搂主,好人

ym_qi 发表于 2009-3-11 21:50

我下不了,哪位也给小弟我发一个吧,万分感谢ym_qi@126.com

leei8210 发表于 2009-3-12 16:32

谢谢楼主共享!

zhuxiaoxun 发表于 2009-3-16 10:09

我这下载不了。感谢哪位好人给小弟发一份:zhu.xiaoxun@163.com。
当然,要先感谢一下楼主。

水光潋滟 发表于 2009-4-30 09:47

给我也发一份,谢谢,邮箱:liling101112@163.com

youxiafly 发表于 2009-5-11 15:07

楼主你好:
      麻烦给我发一份,liuxiaopei2007@163.com
      不胜感激!!

李锦鹏2008268 发表于 2009-5-17 20:06

学长能不能给也发一个啊?我现在做毕业设计,急用啊?谢谢421069750@163.com

dovejin 发表于 2009-5-25 14:05

感谢楼上的兄弟姐妹,我的邮箱 dovejin@126.com,麻烦发给我一份,急用!谢谢~~~

nana40301 发表于 2009-6-10 17:14

急需谢谢 jinsenana@163.com

gauss101 发表于 2009-7-5 11:21

楼主,我也需要一份谢谢!

shaohaijian2004@163.com:@)
页: [1] 2
查看完整版本: 神经网络基本算法源程序