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

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

// isip include files
//
#ifndef ISIP_SDB
#include <Sdb.h>
#endif

#ifndef ISIP_KERNEL
#include <Kernel.h>
#endif

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

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

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

#ifndef ISIP_AUDIO_DATABASE
#include <AudioDatabase.h>
#endif

#ifndef ISIP_FEATURE_FILE
#include <FeatureFile.h>
#endif

#ifndef ISIP_FILENAME
#include <Filename.h>
#endif

#ifndef ISIP_FLOAT
#include <Float.h>
#endif

#ifndef ISIP_STATISTICAL_MODEL
#include <StatisticalModel.h>
#endif

#ifndef ISIP_SUPPORT_VECTOR_MODEL
#include <SupportVectorModel.h>
#endif

#ifndef ISIP_KERNEL
#include <Kernel.h>
#endif

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

// SupportVectorMachine: a class to compute the support vectors in the
// data set using the Sequential Minimization Optimization (SMO) algorithm.
//
// References:
//
// [1] V. N. Vapnik, "The Nature of Statistical Learning Theory",
// Springer-Verlag, New York, 1995.
//
// [2] J. C. Platt, "Fast Training of Support Vector Machines using
// Sequential Minimal Optimization".  In B. Scholkopf, C. J. C.
// Burges and A. J. Smola, editors, "Advances in Kernel Methods
// - Support Vector Learning", pp 185-208, MIT Press, 1998.
//
// [3] N. Cristianini, J. Shawe-Taylor, "An Introduction to Support Vector
// Machines", Cambridge Press, 2000.
//
// [4] C. J. C. Burges, "A Tutorial on Support Vector Machines for
// Pattern Recognition". Available on-line at (Microsoft Research):
// http://www.research.microsoft.com/
//
class SupportVectorMachine {
  
  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------
public:
  
  // define the class name
  //
  static const String CLASS_NAME;

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

  // define the algorithm choices
  //  
  enum ALGORITHM { SEQUENTIAL_MINIMAL_OPTIMIZATION = 0,
		   DEF_ALGORITHM = SEQUENTIAL_MINIMAL_OPTIMIZATION };
  
  // define the implementation choices
  //  
  enum IMPLEMENTATION { LINEAR = 0, POLYNOMIAL, RBF, SIGMOID,  
			DEF_IMPLEMENTATION = LINEAR };

  // define output type choices
  //
  enum TYPE { TEXT = 0, BINARY, DEF_TYPE = BINARY };
  
  // define the static NameMap objects
  //
  static const NameMap IMPL_MAP;
  static const NameMap ALGO_MAP;
  static const NameMap TYPE_MAP;
  
  //----------------------------------------
  //
  // i/o related constants
  //
  //----------------------------------------  
  
  static const String DEF_PARAM;
  static const String DEF_COMMENT_TAG;

  static const String PARAM_OUTPUT_TYPE;
  static const String PARAM_OUTPUT_FILE;
  static const String PARAM_AUDIO_DB;
  static const String PARAM_PENALTY;
  static const String PARAM_EPSILON;
  static const String PARAM_TOLERANCE;
  static const String PARAM_POLYNOMIAL_DEGREE;
  static const String PARAM_RBF_GAMMA;
  static const String PARAM_SIGMOID_KAPPA;
  static const String PARAM_SIGMOID_DELTA;  
  static const String PARAM_ALGORITHM;
  static const String PARAM_IMPLEMENTATION;

  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------  

  static const long DEF_MAX_POINTS = 0;
  static const long DEF_CAPACITY = 1000;
  
  static const float DEF_BIAS = 0.0;
  static const float DEF_PENALTY = 0.05;  
  static const float DEF_EPSILON = 0.001;
  static const float DEF_TOLERANCE = 0.001;
  static const float DEF_POLYNOMIAL_DEGREE = 3.0;
  static const float DEF_RBF_GAMMA = 0.5;
  static const float DEF_SIGMOID_KAPPA = 1.0;
  static const float DEF_SIGMOID_DELTA = 1.0;  
  
  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:

  // algorithm name
  //
  ALGORITHM algorithm_d;
  
  // implementation name
  //
  IMPLEMENTATION implementation_d;

  // output type
  //
  TYPE output_type_d;

  // output file
  //
  Filename output_file_d;

  // audio database file
  //
  Filename audio_db_file_d;
  
  // audio database
  //
  AudioDatabase audio_db_d;
  
  // kernel function: we assume that the same kernel is used for
  // all training points. this only makes sense though since anything else
  // would mean different training points operating in different spaces.
  //
  Kernel kernel_d;
  
  // default polynomial degree
  //
  Float polynomial_degree_d;
  
  // default rbf gamma
  //
  Float rbf_gamma_d;
  
  // default sigmoid kappa
  //
  Float sigmoid_kappa_d;

  // default sigmoid delta
  //
  Float sigmoid_delta_d;
  
  // lagrange multipliers
  //
  VectorFloat alpha_d;

  // maximum penalty for an error
  //
  Float penalty_d;  

  // default tolearnce parameter
  //
  Float tol_d;

  // default epsilon parameter
  //
  Float eps_d;

  // maximum number of points
  //
  Long max_points_d;
  
  // default bias parameter
  //
  Float bias_d;
  
  // error cache parameter
  //
  VectorFloat error_cache_d;

  // input observations and their labels
  //
  Vector<VectorFloat> points_d;
  VectorFloat target_d;  

  // verbosity
  //
  static Integral::DEBUG verbosity_d;
  
  // 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
  //
  ~SupportVectorMachine() {}
  
  // method: default constructor
  //
  SupportVectorMachine();
  
  // method: copy constructor
  //
  SupportVectorMachine(const SupportVectorMachine& arg) {
    assign(arg);
  }
  
  // method: assign
  //
  boolean assign(const SupportVectorMachine& copy_node) {
    return Error::handle(name(), L"assign", Error::ARG, __FILE__, __LINE__);
  }
  
  // method: operator=
  //
  SupportVectorMachine& operator= (const SupportVectorMachine& 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;
  
  // method: eq
  //
  boolean eq(const SupportVectorMachine& arg) const {
    return Error::handle(name(), L"eq", Error::ARG, __FILE__, __LINE__);
  }
  
  // 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: getAlgorithm
  //
  ALGORITHM getAlgorithm() {
    return algorithm_d;
  }

  // method: setAlgorithm
  //
  boolean setAlgorithm(ALGORITHM arg) {
    return (algorithm_d = arg);
  }

  // method: getImplementation
  //
  IMPLEMENTATION getImplementation() {
    return implementation_d;
  }
  
  // method: setImplementation
  //
  boolean setImplementation(IMPLEMENTATION arg) {
    return (implementation_d = arg);
  }
  
  // method: setPenalty
  //
  boolean setPenalty(float arg) {
    if (arg != DEF_PENALTY) {
      penalty_d = arg;
    }
    return true;
  }

  // method: setEpsilon
  //
  boolean setEpsilon(float arg) {
    if (arg != DEF_EPSILON) {
      eps_d = arg;
    }
    return true;
  }  

  // method: setTolerance
  //
  boolean setTolerance (float arg) {
    if (arg != DEF_TOLERANCE) {
      tol_d = arg;
    }
    return true;
  }
  
  // method: setDegree
  //
  boolean setDegree(float arg) {
    if (arg != DEF_POLYNOMIAL_DEGREE) {
      polynomial_degree_d = arg;
    }
    return true;
  }

  // method: setKappa
  //
  boolean setKappa(float arg) {
    if (arg != DEF_SIGMOID_KAPPA) {
      sigmoid_kappa_d = arg;
    }
    return true;
  }

  // method: setDelta
  //
  boolean setDelta(float arg) {
    if (arg != DEF_SIGMOID_DELTA) {
      sigmoid_delta_d = arg;
    }
    return true;
  }

  // method: setGamma
  //
  boolean setGamma(float arg) {
    if (arg != DEF_RBF_GAMMA) {
      rbf_gamma_d = arg;
    }
    return true;
  }

  // method: setVerbosity
  //
  boolean setVerbosity(Integral::DEBUG verbosity) {
    verbosity_d = verbosity;
    return true;
  }

  // method: setOutputFile
  //
  boolean setOutputFile(Filename& arg) {
    return output_file_d.assign(arg);
  }  

  // method: setOutputType
  //
  boolean setOutputType(TYPE arg) {
    output_type_d = arg;
    return true;
  }  
  
  // this method initializes the kernel parameters
  //
  boolean init();

  // this method load the feature vectors in RAW format
  //
  boolean loadRawFeatures(Filename& arg);
  
  // this method load the feature vectors used used in the optimization process
  //
  boolean loadFeatures(Sdb& in_sdb, Sdb& out_sdb);
  
  // this method loads the training data and determines the support vectors
  // currently using the Sequential Minimal Optimization algorithm
  //
  boolean train();

  // this method writes the support vector model to file
  //
  boolean writeModel();
  
  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:

  // this is the main routine of the Sequential Minimal Optimization algorithm
  //
  boolean sequentialMinimalOptimization();

  // method determines the SVM output for the training example
  //
  float evaluateOutput(VectorFloat& point);

  // method that jointly optimizes two Lagrange multipliers and
  // maintains the feasibility of the dual QP
  //
  int takeStep(int i1, int i2);

  // method to examine a specific Lagrange multiplier and check if
  // it violates the KKT condition
  //
  int examineExample(int i2);
};

// end of include file
// 
#endif






