// file: $isip_ifc/class/algo/CorrelationDimension/CorrelationDimension.h
// version: $Id: CorrelationDimension.h 10555 2006-04-19 08:39:03Z pannuri $
//

// make sure definitions are only made once
//
#ifndef ISIP_CORRELATION_DIMENSION
#define ISIP_CORRELATION_DIMENSION
#ifndef ISIP_ALGORITHM_BASE

#include <AlgorithmBase.h>
#endif

// CorrelationDimension: a class that computes an invariant of a
// chaotic system, the correlation dimension.
// the dimension of a strange attractor
// is a measure of its geometric scaling properties or its complexity. in this
// class we calculate one of the types of dimensions, the correlation
// dimension.
//
// J. Theiler,
// Estimating fractal dimension, Lincoln Laboratory,
// MIT, Lexington, Massachusetts, USA, pp. 1066-1069, 1990.
//
// the correlation integral and Rps classes are used for
// estimating the correlation dimension.
// the user first needs to reconstruct the phase space and
// pass it as one of the input arguments.
//
// there are three different implementations for
// estimating the correlation dimension. the first method uses the backward
// differentiation and the second method uses a central differentiation and
// the third implementation uses smooth version of it.
//
// P.S. Addison,
// Fractals and Chaos, an illustrated course.,
// Institute of Physics Publishing, Bristol, UK, pp. 163-171, 1997.
//
// the correlation dimension is given by:
//
//      d(N, r) =   lim      lim       log C(N, r)
//                 r -> 0  N -> inf   -----------
//                                        log r
//
// extracting dimension directly from the equation above is 
// inaccurate.
//
// H. Kantz and T. Schreiber,
// Nonlinear Time Series Analysis, 2nd Edition.,
// Cambridge University Press, Cambridge, UK, pp. 77-85, 1999.
//
// therefore we use a slightly different formula where we
// calculate the local slopes and is given as follows:
//
//           d(N, r) =    log C(N, 2r) - log C(N, r/2)
//                       -----------------------------
//                            log 2r - log r/2
//
// 

class CorrelationDimension : public AlgorithmBase {
  
  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------
public:
  
  // define the class name
  //
  static const String CLASS_NAME;

  //----------------------------------------
  //
  // other important constants
  //
  //----------------------------------------
  
  // define algorithm choices
  //
  enum ALGORITHM { NORMAL = 0, DEF_ALGORITHM = NORMAL };

  // define implementation choices
  //
  enum IMPLEMENTATION { BACKWARD = 0, CENTRAL, SMOOTH, DEF_IMPLEMENTATION = BACKWARD };

  // define scaling choices
  //
  enum SCALING { LINSCALE = 0, LOGSCALE, DEF_SCALING = LINSCALE };

  // define static NameMap objects
  //
  static const NameMap ALGO_MAP;
  static const NameMap IMPL_MAP;
  static const NameMap SCAL_MAP;
   
  //----------------------------------------
  //
  // i/o related constants
  //
  //----------------------------------------  

  static const String DEF_PARAM;
  static const String PARAM_ALGORITHM;  
  static const String PARAM_IMPLEMENTATION;
  static const String PARAM_SCALING;
  static const String PARAM_EPSILON_MIN;
  static const String PARAM_EPSILON_MAX;
  static const String PARAM_EPSILON_RES;
  static const String PARAM_DELTA;
  static const String PARAM_THEILER_CORRECTION;
    
  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------  

  // define the default value(s) of the class data
  //
  static const float DEF_EPSILON_MIN = 1.0 ;
  static const float DEF_EPSILON_MAX = 10.0; 
  static const long DEF_EPSILON_RES = 5;
  static const float DEF_DELTA = 0.1;
  static const long DEF_THEILER_CORRECTION = 150;

  // define default argument(s)
  //
  static const AlgorithmData::COEF_TYPE DEF_COEF_TYPE = AlgorithmData::SIGNAL;
  
  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  
  static const long ERR = 73900;
  static const long ERR_EPSMIN = 73901;
  static const long ERR_EPSMAX = 73902;
  static const long ERR_EPSRES = 73903;
  static const long ERR_EPS = 73904;
  static const long ERR_DELTA_EPSMIN = 73905;
  static const long ERR_DELTA_EPSMAX = 73906;
  
  
  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:

  // algorithm name
  //
  ALGORITHM algorithm_d;

  // implementation type
  //
  IMPLEMENTATION implementation_d;

  // scaling type
  //
  SCALING scaling_d;

  // parameters related to the algorithm specification
  //
  Float epsilon_min_d;        // Radius of the neighborhood for correlation sum
  Float epsilon_max_d;        // Radius of the neighborhood for correlation sum
  Long epsilon_res_d;        // Resolution for the region min-to-max
  Float delta_d;             // the delta value for the  epsilon
  Long theiler_correction_d; // Theiler's correction for correlation sum

  // 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);
  
  // debug methods:
  //  setDebug is inherited from the AlgorithmBase class
  //
  boolean debug(const unichar* msg) const;
  
  // method: destructor
  //
  ~CorrelationDimension() {}

  // default constructor
  //
 CorrelationDimension(ALGORITHM algorithm = DEF_ALGORITHM,
		      IMPLEMENTATION implementation = DEF_IMPLEMENTATION,
		      SCALING scaling = DEF_SCALING,
		      float epsilon_min = DEF_EPSILON_MIN,
		      float epsilon_max = DEF_EPSILON_MAX,
		      long epsilon_res = DEF_EPSILON_RES,
		      float delta = DEF_DELTA,
		      long theiler_correction = DEF_THEILER_CORRECTION) {
    
    // initialize protected data
    //
    algorithm_d = DEF_ALGORITHM;
    implementation_d = DEF_IMPLEMENTATION;
    scaling_d = DEF_SCALING;
    epsilon_min_d = epsilon_min;
    epsilon_max_d = epsilon_max;
    epsilon_res_d = epsilon_res;
    delta_d = delta;
    theiler_correction_d = theiler_correction;
    is_valid_d = false;
  }

  // method: copy constructor
  //
  CorrelationDimension(const CorrelationDimension& arg) {
    assign(arg);
  }
  
  // assign methods
  //
  boolean assign(const CorrelationDimension& arg);
  
  // method: operator=
  //
  CorrelationDimension& operator= (const CorrelationDimension& arg) {
    assign(arg);
    return *this;
  }

  // i/o methods
  //
  long sofSize() const;
  
  boolean read(Sof& sof, long tag, const String& name = CLASS_NAME);
  
  boolean write(Sof& sof, long tag, const String& name = CLASS_NAME) const;
  
  boolean readData(Sof& sof, const String& pname = DEF_PARAM,
                   long size = SofParser::FULL_OBJECT,
                   boolean param = true,
		   boolean nested = false);

  boolean writeData(Sof& sof, const String& pname = DEF_PARAM) const;
  
  // equality methods
  //
  boolean eq(const CorrelationDimension& arg) const;
  
  // 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);
  }

  // other memory management methods
  //
  boolean clear(Integral::CMODE ctype = Integral::DEF_CMODE);
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods
  //  set methods
  //
  //---------------------------------------------------------------------------

  // method: setAlgorithm
  //
  boolean setAlgorithm(ALGORITHM algorithm) {
    algorithm_d = algorithm;
    is_valid_d = false;
    return true;  
  }

  // method: setImplementation
  //
  boolean setImplementation(IMPLEMENTATION implementation) {
    implementation_d = implementation;
    is_valid_d = false;
    return true;  
  }

  // method: setScaling
  //
  boolean setScaling(SCALING scaling) {
    scaling_d = scaling;
    is_valid_d = false;
    return true;  
  }
  
  // method: setEpsilonMin
  //
  boolean setEpsilonMin(float epsilon_min) {
    epsilon_min_d = epsilon_min;
    is_valid_d = false;
    return true;
  }

  // method: setEpsilonMax
  //
  boolean setEpsilonMax(float epsilon_max) {
    epsilon_max_d = epsilon_max;
    is_valid_d = false;
    return true;
  }

  // method: setEpsilonRes
  //
  boolean setEpsilonRes(long epsilon_res) {
    epsilon_res_d = epsilon_res;
    is_valid_d = false;
    return true;
  }

  // method: setDelta
  //
  boolean setDelta(float delta) {
    delta_d =  delta;
    is_valid_d = false;
    return true;
  }
  
  // method: setTheilerCorrection
  //
  boolean setTheilerCorrection(long theiler_correction) {
    theiler_correction_d =  theiler_correction;
    is_valid_d = false;
    return true;
  }

  // method: set
  //
  boolean set(ALGORITHM algorithm = DEF_ALGORITHM,
	      IMPLEMENTATION implementation = DEF_IMPLEMENTATION,
	      SCALING scaling = DEF_SCALING,
	      float epsilon_min = DEF_EPSILON_MIN,
	      float epsilon_max = DEF_EPSILON_MAX,
	      long epsilon_res = DEF_EPSILON_RES,
	      float delta = DEF_DELTA,
	      long theiler_correction = DEF_THEILER_CORRECTION) {
    
    algorithm_d = algorithm;
    implementation_d = implementation;
    scaling_d = scaling;
    epsilon_min_d = epsilon_min;
    epsilon_max_d = epsilon_max;
    epsilon_res_d = epsilon_res;
    delta_d = delta;
    theiler_correction_d = theiler_correction;
    is_valid_d = false;
    return true;
  }
 
  //---------------------------------------------------------------------------
  //
  // class-specific public methods
  //  get methods
  //
  //---------------------------------------------------------------------------  
  // method: getAlgorithm
  //
  ALGORITHM getAlgorithm() const {
    return algorithm_d;
  }

  // method: getImplementation
  //
  IMPLEMENTATION getImplementation() const {
    return implementation_d;
  }

  // method: getScaling
  //
  SCALING getScaling() const {
    return scaling_d;
  }
  
  // method: getEpsilonMin
  //
  float getEpsilonMin() const {
    return epsilon_min_d;
  }

  // method: getEpsilonMax
  //
  float getEpsilonMax() const {
    return epsilon_max_d;
  }

  // method: getEpsilonRes
  //
  long getEpsilonRes() const {
    return epsilon_res_d;
  }

  // method: getTheilerCorrection
  //
  float getDelta() const {
    return delta_d;
  }
  
  // method: getTheilerCorrection
  //
  long getTheilerCorrection() const {
    return theiler_correction_d;
  }

  // method: get
  //
  boolean get(ALGORITHM& algorithm,
	      IMPLEMENTATION& implementation,
	      SCALING& scaling,
	      float& epsilon_min,
	      float& epsilon_max,
	      long& epsilon_res,
	      float& delta,
	      long& theiler_correction) {	     
    algorithm = algorithm_d;
    implementation = implementation_d;
    scaling = scaling_d;
    epsilon_min = epsilon_min_d;
    epsilon_max = epsilon_max_d;
    delta = delta_d;
    theiler_correction = theiler_correction_d;
    return true;
  }
 
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  computation methods
  //
  //---------------------------------------------------------------------------

  boolean compute(VectorFloat& output, const MatrixFloat& input,
		  AlgorithmData::COEF_TYPE input_coef_type = DEF_COEF_TYPE,
		  long index = DEF_CHANNEL_INDEX);
  
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  public methods required by the AlgorithmBase interface contract
  //
  //---------------------------------------------------------------------------

  // assign method
  //
  boolean assign(const AlgorithmBase& arg);

  // equality method
  //
  boolean eq(const AlgorithmBase& arg) const;

  // method: className
  //
  const String& className() const {
    return CLASS_NAME;
  }

  // no initialization method is needed since none of the
  // algorithms currently supported require a history

  // apply method
  //
  boolean apply(Vector<AlgorithmData>& output,
		const Vector< CircularBuffer<AlgorithmData> >& input);

  // method to set the parser
  //
  boolean setParser(SofParser* parser);

  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:

  // common i/o methods
  //
  boolean readDataCommon(Sof& sof, const String& pname,
			 long size = SofParser::FULL_OBJECT,
			 boolean param = true, boolean nested = false);
  
  boolean writeDataCommon(Sof& sof, const String& pname) const;

  boolean computeCorrDimBackward(VectorFloat& correlationdimension,
				const MatrixFloat& input);
  boolean computeCorrDimCentral(VectorFloat& correlationdimension,
				const MatrixFloat& input);
  boolean computeCorrDimSmooth(VectorFloat& correlationdimension,
				const MatrixFloat& input);

  boolean compute(VectorFloat& output_a,
		  const CircularBuffer<AlgorithmData>& input_a,
		  AlgorithmData::COEF_TYPE coef_type_a,
		  long channel_index_a);
};

// end of include file
// 
#endif

