/** 
* @file RandomClustering.h
* @brief Clustering by randomly picking some samples from the set of features as representatives
* @author Alexander Freytag
* @date 03-06-2013 (dd-mm-yyyy)
*/
#ifndef RANDOMCLUSTERERNINCLUDE
#define RANDOMCLUSTERERNINCLUDE

#include <core/basics/Config.h>
#include <core/vector/Distance.h>
#include <core/vector/MatrixT.h>
#include <core/vector/VectorT.h>
  
#include "ClusterAlgorithm.h"

namespace OBJREC {

/**
  * @class RandomClustering
  * @brief Clustering by randomly picking some samples from the set of features as representatives
  * @author Alexander Freytag
  * @date 03-06-2013 (dd-mm-yyyy)
*/    
class RandomClustering : public ClusterAlgorithm
{

  protected:
      
    /************************
      * 
      *   protected variables
      * 
      **************************/ 
    
      //! desired number of clusters
      int noClusters;
      
      //! specify which distance to use for calculating assignments
      std::string distanceType;
      
      //! the actual distance metric
      NICE::VectorDistance<double> *distancefunction;        
      

      /************************
      * 
      *   protected methods
      * 
      **************************/  
    
      
      //! compute assignments of all given features wrt to the currently known prototypes (cluster medoids) == ~ E-step
      double compute_assignments ( const NICE::VVector & features,
                const NICE::VVector & prototypes,
                std::vector<int> & assignment );

      //! compute number of assignments for every currently found cluster
      double compute_weights ( const NICE::VVector & features,
            std::vector<double> & weights,
            std::vector<int>    & assignment );


      //! compute (update) prototypes given the current assignments == ~ M-step
      int compute_prototypes ( const NICE::VVector & features,
              NICE::VVector & prototypes,
              std::vector<double> & weights,
              const std::vector<int>    & assignment );

  public:
    
    ///////////////////// ///////////////////// /////////////////////
    //                   CONSTRUCTORS / DESTRUCTORS
    ///////////////////// ///////////////////// /////////////////////    
    
    /** 
     * @brief default constructor
     * @date 13-02-2014 (dd-mm-yyyy )
     * @author Alexander Freytag
     */
    RandomClustering ( );      

    /**
    * @brief simple constructor
    * @param[in] _noClasses the number of clusters to be computed
    * @param[in] _distanceMode a string specifying the distance function to be used (default: euclidean)* 
    * @date 03-06-2013 (dd-mm-yyyy)
    */
    RandomClustering( const int & _noClasses , const std::string & _distanceMode="euclidean" );
    
    /**
    * @brief standard constructor
    * @param[in] conf config file specifying all relevant variable settings
    * @param[in] _section name of the section within the configfile where the settings can be found (default: RandomClustering)
    * @date 03-06-2013 (dd-mm-yyyy)
    */
    RandomClustering( const NICE::Config * _conf, const std::string & _confSection = "RandomClustering");

    
        
    /** simple destructor */
    virtual ~RandomClustering();
      
    /** 
     * @brief Jobs previously performed in the config-version of the constructor, read settings etc.
     * @author Alexander Freytag
     * @date 13-02-2014 ( dd-mm-yyyy )
     */    
    void initFromConfig ( const NICE::Config * _conf, const std::string & _confSection = "RandomClustering");         
        
    ///////////////////// ///////////////////// /////////////////////
    //                      CLUSTERING STUFF
    ///////////////////// ///////////////////// //////////////////         
          
    /**
    * @brief this is the actual method that performs the clustering for a given set of features
    * @author Alexander Freytag
    * @date 03-06-2013 (dd-mm-yyyy)
    * @param   features input features to be clustered
    * @param   prototypes computed prototypes (randomly chosen) for the given samples
    * @param   weights number of assignments for every cluster
    * @param   assignment explicite assignments of features to computed cluster medoids
    */        
    void cluster ( const NICE::VVector & features,
            NICE::VVector & prototypes,
            std::vector<double> & weights,
            std::vector<int>    & assignment );
        
    ///////////////////// INTERFACE PERSISTENT /////////////////////
    // interface specific methods for store and restore
    ///////////////////// INTERFACE PERSISTENT /////////////////////      
    
    /**
    * @brief Load object from external file (stream)
    * @author Alexander Freytag
    * @date 13-02-2014 ( dd-mm-yyyy )
    */
    void restore ( std::istream & is, int format = 0 );

    /**
    * @brief Save object to external file (stream)
    * @author Alexander Freytag
    * @date 13-02-2014 ( dd-mm-yyyy )
    */
    void store ( std::ostream & os, int format = 0 ) const;

    /**
    * @brief Clear object
    * @author Alexander Freytag
    * @date 13-02-2014 ( dd-mm-yyyy )
    */
    void clear ();          

};


} // namespace

#endif
