// file: $isip/class/stat/StatisticalModel/StatisticalModel.h
// version: $Id: StatisticalModel.h 9378 2003-12-23 20:56:11Z alphonso $
//

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

// isip include files
//
#ifndef ISIP_STATISTICAL_MODEL_BASE
#include <StatisticalModelBase.h>
#endif

#ifndef ISIP_STATISTICAL_MODEL_UNDEFINED
#include <StatisticalModelUndefined.h>
#endif

// forward class definitions
//
class VectorDouble;
class MatrixFloat;
class NameMap;
class MixtureModel;
class GaussianModel;
class SupportVectorModel;
class RelevanceVectorModel;
class UniformModel;

// StatisticalModel: a class whose chief goal is to evaluate the likelihood
// of an input vector with respect to a statistical model. this class provides
// a virtual interface to any class that implements the StatisticalModelBase
// interface contract.
//
class StatisticalModel : public StatisticalModelBase {

  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------
public:

  // define the class name
  //
  static const String CLASS_NAME;

  //----------------------------------------
  //
  // other important constants
  //
  //----------------------------------------  

  // define the currently available model types
  //
  enum TYPE { UNKNOWN = 0, GAUSSIAN_MODEL, MIXTURE_MODEL, UNIFORM_MODEL,
	      SUPPORT_VECTOR_MODEL, RELEVANCE_VECTOR_MODEL, DEF_TYPE = UNKNOWN };

  // define the implementation choices
  //
  enum ALGORITHM {MIXTURE_SPLITTING = 0,
		  DEF_ALGORITHM = MIXTURE_SPLITTING};
  
  // define the implementation choices
  //
  enum IMPLEMENTATION {VARIANCE_SPLITTING = 0,
		       DEF_IMPLEMENTATION = VARIANCE_SPLITTING};  
    
  // a static name map
  //
  static const NameMap TYPE_MAP;

  //----------------------------------------
  //
  // i/o related constants
  //
  //----------------------------------------  
  
  static const String PARAM_TYPE;
  static const String DEF_PARAM;
  
  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------  

  // define the default value(s) of the class data
  //
  static const StatisticalModelUndefined NO_STAT_MODEL;

  // define the perturb factor for splitting the models
  //
  static const float DEF_PERTURB_FACTOR = 0.2;
  
  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------  

  static const long ERR = 60300;
  
  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:

  // algorithm name
  //
  ALGORITHM algorithm_d;
  
  // implementation name
  //
  IMPLEMENTATION implementation_d;
  
  // a virtual pointer to a statistical model
  //
  StatisticalModelBase* virtual_model_d;

  // 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: debug
  //  setDebug is inherited from base class
  //
  boolean debug(const unichar* message) const {
    return virtual_model_d->debug(message);
  }

  // method: destructor
  //
  ~StatisticalModel() {
    if (virtual_model_d != (StatisticalModelBase*)&NO_STAT_MODEL) {
      delete virtual_model_d;
    }
  }

  // method: default constructor
  //
  StatisticalModel(TYPE type = DEF_TYPE) {
    algorithm_d = DEF_ALGORITHM;    
    implementation_d = DEF_IMPLEMENTATION;
    virtual_model_d = (StatisticalModelBase*)&NO_STAT_MODEL;
    setType(type);
  }

  // method: copy constructor
  //
  StatisticalModel(const StatisticalModel& arg) {
    virtual_model_d = (StatisticalModelBase*)&NO_STAT_MODEL;
    assign(arg);
  }

  // method: assign
  //
  boolean assign(const StatisticalModel& arg) {
    algorithm_d = arg.algorithm_d;    
    implementation_d = arg.implementation_d;
    return assign(*arg.virtual_model_d);
  }

  // method: operator=
  //
  StatisticalModel& operator=(const StatisticalModel& arg) {
    assign(arg);
    return *this;
  }
  
  // method: eq
  //
  boolean eq(const StatisticalModel& arg) const {
    return virtual_model_d->eq(*arg.virtual_model_d);
  }

  // method: sofSize
  //
  long sofSize() const {
    return (TYPE_MAP.elementSofSize() + virtual_model_d->sofSize());
  }

  // method: sofAccumulatorSize
  //
  long sofAccumulatorSize() const {
    return (TYPE_MAP.elementSofSize() + virtual_model_d->sofAccumulatorSize());
  }

  // method: sofOccupanciesSize
  //
  long sofOccupanciesSize() const {
    return (TYPE_MAP.elementSofSize() + virtual_model_d->sofOccupanciesSize());
  }    

  // other i/o methods
  //
  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;
  
  boolean readAccumulator(Sof& sof, long tag,
		    const String& name = CLASS_NAME);
  boolean writeAccumulator(Sof& sof, long tag,
		     const String& name = CLASS_NAME) const;

  boolean readAccumulatorData(Sof& sof, const String& pname = DEF_PARAM,
		   long size = SofParser::FULL_OBJECT,
		   boolean param = true, boolean nested = false);
  boolean writeAccumulatorData(Sof& sof, const String& pname = DEF_PARAM) const;  
  
  boolean readOccupancies(Sof& sof, long tag,
			  const String& name = CLASS_NAME);
  boolean writeOccupancies(Sof& sof, long tag,
			   const String& name = CLASS_NAME) const;
  
  boolean readOccupanciesData(Sof& sof, const String& pname = DEF_PARAM,
			      long size = SofParser::FULL_OBJECT,
			      boolean param = true, boolean nested = false);
  boolean writeOccupanciesData(Sof& sof, const String& pname = DEF_PARAM) const; 
  
  // method: operator new
  //
  static void* operator new(size_t size) {
    return mgr_d.get();
  }

  // method: operator new[]
  //
  static void* operator new[](size_t size) {
    return mgr_d.getBlock(size);
  }

  // method: operator delete
  //
  static void operator delete(void* ptr) {
    mgr_d.release(ptr);
  }

  // method: operator delete[]
  //
  static void operator delete[](void* ptr) {
    mgr_d.releaseBlock(ptr);
  }

  // method: setGrowSize
  //
  static boolean setGrowSize(long size) {
    return mgr_d.setGrow(size);
  }

  // other memory-management methods
  //
  boolean clear(Integral::CMODE cmode = Integral::DEF_CMODE);

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  methods needed for training models
  //
  //---------------------------------------------------------------------------

  // method: resetAccumulators
  //
  boolean resetAccumulators() {
    return virtual_model_d->resetAccumulators();
  }
  
  // method: getOccupancy
  //
  double getOccupancy() {
    return virtual_model_d->getOccupancy();
  }

  // method: setOccupancy
  //
  boolean setOccupancy(double arg) {
    return virtual_model_d->setOccupancy(arg);
  }  

  // method: getAccessCount
  //
  long getAccessCount() {
    return virtual_model_d->getAccessCount();
  }

  // method: setAccessCount
  //
  boolean setAccessCount(long arg) {
    return virtual_model_d->setAccessCount(arg);
  }

  // method: initialize
  //
  boolean initialize(VectorFloat& param) {
    return virtual_model_d->initialize(param);
  }
  
  // method: accumulate
  //
  boolean accumulate(VectorFloat& data) {
    return virtual_model_d->accumulate(data);
  }
  
  // method: accumulate
  //
  boolean accumulate(VectorDouble& param,
		     VectorFloat& data, boolean precomp) {
    return virtual_model_d->accumulate(param, data, precomp);
  }

  // method: update
  //  
  boolean update(VectorFloat& varfloor, long min_count) {
    return virtual_model_d->update(varfloor, min_count);
  }

  // method: addModelToMixture
  //
  static boolean addModelToMixture(StatisticalModel& model_a,
				   StatisticalModel& mixture_a);

  // method: splitMixtureModel
  //  
  boolean splitMixtureModel(long arg);  
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  additional methods needed to facilitate base class manipulations
  //
  //---------------------------------------------------------------------------

  // method: getAlgorithm
  //
  ALGORITHM getAlgorithm() {
    return algorithm_d;
  }

  // method: getImplementation
  //
  IMPLEMENTATION setImplementation() {
    return implementation_d;
  }
  
  // method: setAlgorithm
  //
  boolean setAlgorithm(ALGORITHM algorithm) {
    algorithm_d = algorithm;
    return true;
  }

  // method: setImplementation
  //
  boolean setImplementation(IMPLEMENTATION implementation) {
    implementation_d = implementation;
    return true;  
  }
  
  // configuration methods
  //
  boolean setType(TYPE type);

  // method: getType
  //
  TYPE getType() const {
    return (TYPE)TYPE_MAP(virtual_model_d->className());
  }

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  these functions interface to the base class interface contract.
  //
  //---------------------------------------------------------------------------

  // method: constructor
  //
  StatisticalModel(const StatisticalModelBase& arg) {
    algorithm_d = DEF_ALGORITHM;    
    implementation_d = DEF_IMPLEMENTATION;
    virtual_model_d = (StatisticalModelBase*)&NO_STAT_MODEL;    
    assign(arg);
  }
  
  // StatisticalModelBase required methods
  //
  boolean assign(const StatisticalModelBase& arg);

  // method: eq
  //
  boolean eq(const StatisticalModelBase& arg) const {
    return virtual_model_d->eq(arg);
  }
  
  // method: setMode
  //
  boolean setMode(MODE mode) {
    return virtual_model_d->setMode(mode);
  }

  // method: getMode
  //
  MODE getMode() const {
    return virtual_model_d->getMode();
  }
			 
  // method: className
  //
  const String& className() const {
    return virtual_model_d->className();
  }

  // method: init
  //
  boolean init() {
    return virtual_model_d->init();
  }

  // method: getMean
  //
  boolean getMean(VectorFloat& mean) {
    return virtual_model_d->getMean(mean);
  }
  
  // method: getCovariance
  //
  boolean getCovariance(MatrixFloat& cov) {
    return virtual_model_d->getCovariance(cov);
  }
  
  // method: getLikelihood
  //
  float getLikelihood(const VectorFloat& input) {
    return virtual_model_d->getLikelihood(input);
  }

  // method: getLogLikelihood
  //
  float getLogLikelihood(const VectorFloat& input) {
    return virtual_model_d->getLogLikelihood(input);
  }

  // method: getMixtureModel
  //
  MixtureModel& getMixtureModel() {
    return *((MixtureModel*)virtual_model_d);
  }
  
  // method: getGaussianModel
  //
  GaussianModel& getGaussianModel() {
    return *((GaussianModel*)virtual_model_d);
  }

  // method: getSupportVectorModel
  //
  SupportVectorModel& getSupportVectorModel() {
    return *((SupportVectorModel*)virtual_model_d);
  }

  // method: getRelevanceVectorModel
  //
  RelevanceVectorModel& getRelevanceVectorModel() {
    return *((RelevanceVectorModel*)virtual_model_d);
  }    
  
  // method: getUniformModel
  //
  UniformModel& getUniformModel() {
    return *((UniformModel*)virtual_model_d);
  }
  
  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:

};

// end of include file
// 
#endif
