// file: $isip/class/pr/NeuralNetwork/NeuralNetwork.h
//

// make sure definitions are only made once
//
#ifndef ISIP_NEURAL_NETWORK
#define ISIP_NEURAL_NETWORK

#ifndef ISIP_STRING
#include <String.h>
#endif

#ifndef ISIP_VECTOR
#include <Vector.h>
#endif

#ifndef ISIP_VECTOR_FLOAT
#include <VectorFloat.h>
#endif

#ifndef ISIP_MATRIX_FLOAT
#include <MatrixFloat.h>
#endif

#ifndef ISIP_MEMORY_MANAGER
#include <MemoryManager.h>
#endif

// NeuralNetwork: a class that implements a massively distributed processor
// made up of simple processing units, which has a natural propensity for
// storing experiential knowladge and making it available for use.
//
// References:
//
// [1] Elaine, Rich and Knight, "Artificial Intelligence", Second Edition,
//     McGraw Hill, New York, 1991.
//
// [2] S. Haykin, "Neural Networks", Second Edition, Prentice Hall,
//     New Jersey, 1999.
//
class NeuralNetwork {
  
  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------
public:
  
  // define the class name
  //
  static const String CLASS_NAME;
  
  //----------------------------------------
  //
  // i/o related constants
  //
  //----------------------------------------  
  
  static const String DEF_PARAM;
  static const String DEF_COMMENT_TAG;
  
  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------  

  static const float DEF_ETA = 0.35;
  static const float DEF_BIAS = 1.0;  
  static const float DEF_MOMENTUM = 0.1;
  
  static const long DEF_EPOCHS = 1;
  static const long DEF_HIDDEN_UNITS = 1; 
  static const long DEF_HIDDEN_LAYERS = 1;
  
  //---------------------------------------------------------------------------
  //
  // public data
  //
  //--------------------------------------------------------------------------
  
  // define the input features
  //
  Vector<VectorFloat> features_d;
  
  // define the reference target
  //
  Vector<VectorFloat> outputs_d;

  // define the test features
  //
  Vector<VectorFloat> test_features_d;
  
  // define the test reference target
  //
  Vector<VectorFloat> test_outputs_d;  
  
  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:

  // a static debug level
  //
  static Integral::DEBUG debug_level_d;
  
  // a static memory manager
  //
  static MemoryManager mgr_d;
  
  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:
  
  // method: name
  //
  static const String& name() {
    return CLASS_NAME;
  }
  
  // other static methods
  //
  static boolean diagnose(Integral::DEBUG debug_level);
  
  // method: setDebug
  //
  static boolean setDebug(Integral::DEBUG level) {
    debug_level_d = level;
    return true;
  }
  
  // method: debug
  //
  boolean debug(const unichar* msg) const {
    return true;
  }
  
  // method: destructor
  //
  ~NeuralNetwork() {}
  
  // method: default constructor
  //
  NeuralNetwork();
  
  // method: copy constructor
  //
  NeuralNetwork(const NeuralNetwork& arg) {
    assign(arg);
  }
  
  // method: assign
  //
  boolean assign(const NeuralNetwork& copy_node) {
    return true;
  }
  
  // method: operator=
  //
  NeuralNetwork& operator= (const NeuralNetwork& arg) {
    assign(arg);
    return *this;
  }
  
  // method: new
  //
  static void* operator new(size_t size) {
    return mgr_d.get();
  }
  
  // method: new[]
  //
  static void* operator new[](size_t size) {
    return mgr_d.getBlock(size);
  }
  
  // method: delete
  //
  static void operator delete(void* ptr) {
    mgr_d.release(ptr);
  }
  
  // method: delete[]
  //
  static void operator delete[](void* ptr) {
    mgr_d.releaseBlock(ptr);
  }
  
  // method: setGrowSize
  // 
  static boolean setGrowSize(long grow_size) {
    return mgr_d.setGrow(grow_size);
  }

  // method: clear
  //
  boolean clear(Integral::CMODE cmode = Integral::DEF_CMODE) {
    return true;
  }

  //---------------------------------------------------------------------------
  //
  // class-specific public methods
  //
  //---------------------------------------------------------------------------

  // method: setEpochs
  //
  boolean setEpochs(long arg) {
    epochs_d = arg;
    return true;
  }

  // method: getEpochs
  //
  long getEpochs() {
    return epochs_d;
  }

  // method: setLearningRate
  //
  boolean setLearningRate(float arg) {
    eta_d = arg;
    return true;
  }

  // method: getLearningRate
  //
  float getLearningRate() {
    return eta_d;
  }

  // method: setMomentum
  //
  boolean setMomentum(float arg) {
    momentum_d = arg;
    return true;
  }

  // method: getMomentum
  //
  float getMomentum() {
    return momentum_d;
  }

  // method: setBias
  //
  boolean setBias(float arg) {
    bias_d = arg;
    return true;
  }

  // method: getBias
  //
  float getBias() {
    return bias_d;
  }        

  // this method initialize the neural network
  //
  boolean init(long epochs, long units, long layers = DEF_HIDDEN_LAYERS,
	       float bias = DEF_BIAS, float rate = DEF_ETA,
	       float momentum = DEF_MOMENTUM); 
  
  // this method load the feature vectors used to train the neural network
  //
  boolean loadFeatures(String& arg);

  // this method load the training target values
  //
  boolean loadOutputs(String& arg);

  // this method load the feature vectors used to test the neural network
  //
  boolean loadTestFeatures(String& arg);

  // this method load the testing target values
  //
  boolean loadTestOutputs(String& arg);  
  
  // this method loads the training data and determines the weights
  // for the neural network
  //
  boolean train(String& train, String& output, String& model);

  // this method loads the models and testing data and generates results
  //
  boolean test(String& model, String& test, String& output);

  // write the model to file
  //
  boolean writeModel(String& arg);
  
  //---------------------------------------------------------------------------
  //
  // private data
  //
  //---------------------------------------------------------------------------
private:

  // define the bias parameter
  //
  float bias_d;

  // define the learning rate and momentum
  //
  float eta_d;
  float momentum_d;

  // define the number of epochs
  //
  long epochs_d;      

  // define the weights from the input to the hidden layer
  //
  MatrixFloat w1_d;

  // define the weights from the hidden to the output layer
  //
  MatrixFloat w2_d;  

  // define the weights within the hidden layers
  //
  Vector<MatrixFloat> h1_d;
  
  // define the hidden layer/layers
  //
  Vector<VectorFloat> hidden_layers_d;

  // define the input layer
  //
  VectorFloat input_layer_d;

  // define the output layer
  //
  VectorFloat output_layer_d;
  
  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:

  // method the randomize the 
};

// end of include file
// 
#endif
