//
// File name: neuro.h
//
// Discription: Base classes
//
// Programmer: Vladimir P. Stasevich (SV)
//
// History:
//    Created 03.12.1999 (SV)
//

#ifndef NEURO_H
#define NEURO_H

#include <stdio.h>
#pragma hdrstop

  // состояния объектов
typedef enum TNeuroObjectState
{
   STATE_OK = 0,
   STATE_ERROR = 1,
} TNeuroObjectState;

// типы активационных функций 
typedef enum TActivateFuncTypes
{
   ORIGINAL  = 0,
   HYPERTAN  = 1, 
   HARDLIMIT = 2, 
   THRESHOLD = 3, 
} TActivateFuncTypes;

// тип распределения памяти
typedef enum TDistribMemTypes
{
   INNER  = 0,
   EXTERN = 1, 
} TDistribMemTypes;

/*
typedef enum THorVerTypes
{
   HORIZONTAL = 1,
   VERTICAL   = 0,
} THorVerTypes;

#ifndef max 
   #define max(a,b) (((a) > (b)) ? (a) : (b)) 
   #define min(a,b) (((a) < (b)) ? (a) : (b)) 
#endif 

*/
  
// базовый класс нейронов для большинства сетей
class Neuron
{
   protected:
      float        state;     // состояние
      float        axon;      // выход
      TNeuroObjectState stat;      // признак ошибки

   public:
      Neuron( void ){ state = 0.; axon = 0.; stat = STATE_OK; };
      virtual float Sigmoid( void )=0;
      TNeuroObjectState GetStatus( void ){ return stat; };
};

class LayerBP;
class NetBP;
class TRecognitionNet;

// нейрон для полносвязной сети прямого распространения
class NeuronFF : public Neuron
{
   protected:
      unsigned           rang;     // число весов
      float             *synapses; // веса
      float**            inputs;   // массив указателей на выходы нейронов предыд. слоя
      void _allocateNeuron( unsigned );
      void _deallocate( void );

   public:
      NeuronFF( unsigned numInputs );
      NeuronFF( void ){ rang = 0; synapses = NULL; inputs = NULL; stat = STATE_OK; };
      ~NeuronFF();
      virtual void Propagate( void );
      void SetInputs( float *array );
      void InitNeuron( unsigned numSynapses );
      virtual void RandomizeAxon( void );
      virtual void Randomize( float );
      virtual float Sigmoid( void );
      virtual float D_Sigmoid( void );
//      virtual void PrintSynapses( int, int );
//      virtual void PrintAxons( int, int );
};

class NeuronBP: public NeuronFF
{
   friend LayerBP;
   friend NetBP;
   friend TRecognitionNet;
   float  error;
   float *deltas; // изменения весов 
   void _allocateNeuron( unsigned ); 
   void _deallocate( void ); 
      
   public:
      NeuronBP( unsigned numInputs );
      NeuronBP( void ){ deltas = NULL; error=0.; };
      ~NeuronBP();
      void InitNeuron( unsigned numSynapses ); 
      int IsConverged( void ); 
}; 
  
class LayerFF 
{ 
   protected: 
      unsigned       rang; 
      TNeuroObjectState   stat;
//      int            x,y,dx,dy; 
      unsigned char *name; // имя слоя 
      
   public: 
      LayerFF( void ){ rang = 0; name = NULL; stat = STATE_OK; };
      unsigned GetRang( void ){ return rang; }; 
//      void SetShowDim( int _x, int _y, int _dx, int _dy ) 
//      { x = _x; y = _y; dx = _dx; dy = _dy; }; 
      
      void SetName( unsigned char *s ){ name = s; }; 
      unsigned char *GetName(void) 
      {
         if(name) 
            return name; 
         else 
            return (unsigned char *)&("NoName");
      }; 
      
      TNeuroObjectState GetStatus( void ){ return stat; }; 
       
//      int GetX( void ){ return x; }; 
//      int GetY( void ){ return y; }; 
//      int GetDX( void ){ return dx; }; 
//      int GetDY( void ){ return dy; };
}; 
  
class LayerBP: public LayerFF 
{ 
   friend NetBP;
   friend TRecognitionNet;

   protected: 
      unsigned       neuronrang; // число синапсов в нейронах 
      int            allocation; 
      NeuronBP      *neurons; 
      
   public:
      LayerBP( unsigned nRang, unsigned nSinapses ); 
      LayerBP( NeuronBP *Neu, unsigned nRang, unsigned nSinapses); 
      LayerBP( void ) 
      { neurons = NULL; neuronrang = 0; allocation = EXTERN; }; 
      ~LayerBP(); 
      void Propagate( void ); 
      void Randomize( float ); 
      void RandomizeAxons( void ); 
      void Normalize( void ); 
      void Update( void ); 
      int IsConverged( void ); 
//      virtual void Show( void );
//      virtual void PrintSynapses( int, int ); 
//      virtual void PrintAxons( int x, int y, int direction ); 
}; 

class SomeNeuralNet 
{
   protected:
      unsigned        rang;
      TNeuroObjectState    stat;

   public:
      SomeNeuralNet( void )
      { rang = 0; stat = STATE_OK; };
      
      unsigned GetRang( void ){ return rang; }; 

      TNeuroObjectState GetStatus( void ){ return stat; }; 
}; 

class NetBP : public SomeNeuralNet
{
   protected:
      LayerBP **layers; 

      int cycle;
   
   // нулевой слой нейронов без синапсов реализует входы 
   public: 
      NetBP( void ){ layers=NULL; cycle = 0; }; 
      NetBP( unsigned nLayers );
      NetBP( unsigned n, unsigned n1, ... ); 
      ~NetBP(); 
      int SetLayer( unsigned n, LayerBP *pl ); 
      LayerBP *GetLayer( unsigned  n )
      {
         if( n < rang ) 
            return layers[n]; 
         else 
            return NULL; 
      } 

      void SetCycle( int c )
      { cycle = c; };

      int GetCycle()
      { return cycle; };

      void NextCycle()
      { cycle--; };
      
      void Propagate( void ); 
      int FullConnect( void ); 
      void SetNetInputs( float *mvalue ); 
      void CalculateError( float *Target ); 
      void Learn( void ); 
      void Update( void ); 
      void Randomize( float ); 
      void Cycle( float *Inp, float *Out ); 
      int SaveToFile( const char *fileName );
      int LoadFromFile( const char *fileName ); 
//      int LoadNextPattern( float *IN, float *OU ); 
      int IsConverged( void ); 
//      void AddNoise( void ); 
//      virtual void PrintSynapses( int x=0,... ){}; 
//      virtual float Change( float In ); 
}; 

extern float lastDiff;

// Глобальные параметры для обратного распространения 
int SetSigmoidType(int st); 
float SetSigmoidAlfa(float Al); 
float SetMiuParm(float Mi); 
float SetNiuParm(float Ni); 
float SetLimit(float Li); 
unsigned SetDSigma(unsigned d); 

#endif
  
