/**
* @file KCNullSpace.h
* @author Paul Bodesheim
* @date 26/11/2012

*/
#ifndef _NICE_OBJREC_KCNULLSPACEINCLUDE
#define _NICE_OBJREC_KCNULLSPACEINCLUDE

#include "vislearning/math/mathbase/FullVector.h"
#include "vislearning/classifier/classifierbase/KernelClassifier.h"
#include <vector>
#include "core/vector/VVector.h"
#include "core/vector/Eigen.h"
// #include "core/algebra/EigValuesTRLAN.h" 

namespace OBJREC
{

/** @class KCNullSpace
 * Classification and novelty detection with kernel null space methods (Kernel Null Foley Sammon Transform - KNFST)
 *
 * @author Paul Bodesheim
 */
class KCNullSpace : public KernelClassifier
{

  protected:

    /** tell us something about what you are doing */
    bool verbose;

    /** Kernel PCA basisvectors as columns of a matrix */
    NICE::Matrix eigenBasis;
    
    /** store class labels and corresponding number of samples in this map: <classLabel,numClassSamples> */
    std::map<int, int> trainingSetStatistic;
    
    /** null projection directions in columns of a matrix */
    NICE::Matrix nullProjectionDirections;
    
    /** target points in the null space represented as NICE::Vector's associated with the corresponding class label in this map */
    std::map<int, NICE::Vector> targetPoints; 
    
    /** dimension of the null space */
    int dimNullSpace;
    
    /** one-class novelty detection? */
    bool oneClassSetting;
    
    /** count how many training samples are in each class */
    void computeTrainingSetStatistic(const NICE::Vector & y);
    
    /** compute null projection directions using kernel data and labels */
    void computeNullProjectionDirections(const KernelData *kernelData, const NICE::Vector & y);
  
    /** compute target points of training data */
    void computeTargetPoints(const KernelData *kernelData, const NICE::Vector & y);
    
    /** compute Kernel PCA basisvectors as columns of a matrix */
    void computeBasisUsingKernelPCA(const KernelData *kernelData);
    
    /** center kernel matrix such that data in kernel feature space has zero mean */
    void centerKernelMatrix(NICE::Matrix & kernelMatrix);     
    
  public:
    
    /** simplest constructor */
    KCNullSpace() {};

    /** simple constructor */
    KCNullSpace ( const NICE::Config *conf, Kernel *kernelFunction = NULL, const std::string & section = "KCNullSpace" );

    /** copy constructor */
    KCNullSpace ( const KCNullSpace &vcova );

    /** simple destructor */
    virtual ~KCNullSpace();

    /** teach the classifier with a kernel matrix and the corresponding class labels @param y ! */
    void teach ( KernelData *kernelData, const NICE::Vector & y );
    void teach ( KernelData *kernelData, const std::vector<double> & y );

    /** classify an example by using its kernel values with the training set,
     be careful with the order in @param kernelVector */
    ClassificationResult classifyKernel ( const NICE::Vector & kernelVector, double kernelSelf ) const;
    
    /** classify an example concerning novelty (binary decision) by using its kernel values with the training set,
     be careful with the order in @param kernelVector */
    ClassificationResult noveltyDetection ( const NICE::Vector & kernelVector, double kernelSelf ) const;
 
    /** return class labels and corresponding number of class samples */
    std::map<int,int> * getTrainingSetStatistic();
    
    /** return null projection directions in columns of a matrix */
    NICE::Matrix  getNullProjectionDirections();

    /** return target points as NICE::Vector's associated with the corresponding class labels in a map */
    std::map<int, NICE::Vector> * getTargetPoints();
    
    /** true if it is a one-class setting */
    bool isOneClass();
    
    /** return dimension of the null space */
    int getNullSpaceDimension();
    
    void restore ( std::istream&, int );
    void store ( std::ostream&, int ) const;
    void clear();

    /** clone this object */
    virtual KCNullSpace *clone ( void ) const;
    
};

}

#endif
