Quellcode durchsuchen

Persistent versions of ClusterAlgorithm with simple TestUnit

Alexander Freytag vor 11 Jahren
Ursprung
Commit
ec9899a6fb

+ 28 - 1
math/cluster/ClusterAlgorithm.cpp

@@ -16,7 +16,9 @@ using namespace std;
 // old: using namespace ice;
 using namespace NICE;
 
-
+///////////////////// ///////////////////// /////////////////////
+//                   CONSTRUCTORS / DESTRUCTORS
+///////////////////// ///////////////////// /////////////////////
 
 ClusterAlgorithm::ClusterAlgorithm()
 {
@@ -26,3 +28,28 @@ ClusterAlgorithm::~ClusterAlgorithm()
 {
 }
 
+void ClusterAlgorithm::initFromConfig ( const NICE::Config * _conf, const std::string & _confSection )
+{
+  //nothing to do
+}
+
+
+///////////////////// INTERFACE PERSISTENT /////////////////////
+// interface specific methods for store and restore
+///////////////////// INTERFACE PERSISTENT ///////////////////// 
+
+void ClusterAlgorithm::restore ( std::istream & is, int format )
+{
+  //nothing to do
+}
+
+void ClusterAlgorithm::store ( std::ostream & os, int format ) const
+{
+  //nothing to do
+}
+
+void ClusterAlgorithm::clear ()
+{
+  //nothing to do  
+}
+

+ 49 - 8
math/cluster/ClusterAlgorithm.h

@@ -1,15 +1,16 @@
 /** 
 * @file ClusterAlgorithm.h
 * @brief Interface for Cluster-Algorithms
-* @author Erik Rodner
-* @date 10/29/2007
-
+* @author Erik Rodner, Alexander Freytag
+* @date 10/29/2007 (last update on 12-02-2014 ( dd-mm-yyyy ) )
 */
 #ifndef CLUSTERALGORITHMINCLUDE
 #define CLUSTERALGORITHMINCLUDE
 
 // nice-core includes
 #include <core/basics/Exception.h>
+#include <core/basics/Persistent.h>
+#include <core/basics/Config.h>
 // 
 #include <core/vector/VectorT.h>
 #include <core/vector/MatrixT.h>
@@ -18,25 +19,65 @@
 
 namespace OBJREC {
 
-  /** Interface for Cluster-Algorithms */
-  class ClusterAlgorithm
-  {
+/** Interface for Cluster-Algorithms */
+class ClusterAlgorithm : public NICE::Persistent
+{
 
-      protected:
+  protected:
 
-      public:
+  public:
+    
+    ///////////////////// ///////////////////// /////////////////////
+    //                   CONSTRUCTORS / DESTRUCTORS
+    ///////////////////// ///////////////////// /////////////////////        
     
     /** simple constructor */
     ClusterAlgorithm();
         
     /** simple destructor */
     virtual ~ClusterAlgorithm();
+    
+    /** 
+     * @brief Jobs previously performed in the config-version of the constructor, read settings etc. -- nothing to do here
+     * @author Alexander Freytag
+     * @date 12-02-2014 ( dd-mm-yyyy )
+     */    
+    virtual void initFromConfig ( const NICE::Config * _conf, const std::string & _confSection = "ClusterAlgorithm");    
+    
+    ///////////////////// ///////////////////// /////////////////////
+    //                      CLUSTERING STUFF
+    ///////////////////// ///////////////////// //////////////////    
 
     virtual void cluster ( 
             const NICE::VVector & features,
             NICE::VVector & prototypes,
             std::vector<double> & weights,
             std::vector<int>    & assignment ) = 0;
+            
+    ///////////////////// INTERFACE PERSISTENT /////////////////////
+    // interface specific methods for store and restore
+    ///////////////////// INTERFACE PERSISTENT /////////////////////
+
+    /**
+    * @brief Load object from external file (stream)  -- nothing to do here
+    * @author Alexander Freytag
+    * @date 12-02-2014 ( dd-mm-yyyy )
+    */
+    void restore ( std::istream & is, int format = 0 );
+
+    /**
+    * @brief Save object to external file (stream)  -- nothing to do here
+    * @author Alexander Freytag
+    * @date 12-02-2014 ( dd-mm-yyyy )
+    */
+    void store ( std::ostream & os, int format = 0 ) const;
+
+    /**
+    * @brief Clear object  -- nothing to do here
+    * @author Alexander Freytag
+    * @date 12-02-2014 ( dd-mm-yyyy )
+    */
+    void clear ();             
       
   };
 

+ 70 - 6
math/cluster/GenericClusterAlgorithmSelection.h

@@ -42,7 +42,7 @@ namespace OBJREC {
         * @author Alexander Freytag
         */
         static
-        OBJREC::ClusterAlgorithm *selectClusterAlgo ( const NICE::Config *conf, std::string section = "clustering" )
+        OBJREC::ClusterAlgorithm *selectClusterAlgorithm ( const NICE::Config *conf, std::string section = "clustering" )
         {
           // return value
           OBJREC::ClusterAlgorithm *clusterAlgo = NULL;
@@ -52,19 +52,19 @@ namespace OBJREC {
           
           std::cerr << "clusterTechnique: " << clusterTechnique << std::endl;
                   
-          if ( clusterTechnique == "kmeans" )
+          if ( ( clusterTechnique == "kmeans" ) || ( clusterTechnique == "KMeans" ) )
           {
             clusterAlgo = new OBJREC::KMeans ( conf );
           }        
-          else if ( clusterTechnique == "kmeansHeuristic" )
+          else if ( ( clusterTechnique == "kmeansHeuristic" )|| ( clusterTechnique == "KMeansHeuristic" ) )
           {
             clusterAlgo = new OBJREC::KMeansHeuristic ( conf );
           }   
-          else if ( clusterTechnique == "kmeansMatlab" )
+          else if ( ( clusterTechnique == "kmeansMatlab" )|| ( clusterTechnique == "KMeansMatlab" ) )
           {
             clusterAlgo = new OBJREC::KMeansMatlab ( conf );
           }            
-          else if ( clusterTechnique == "kmedian" )
+          else if ( ( clusterTechnique == "kmedian" )|| ( clusterTechnique == "KMedian" ) )
           {
             clusterAlgo = new OBJREC::KMedian ( conf );
           }     
@@ -72,7 +72,7 @@ namespace OBJREC {
           {
             clusterAlgo = new OBJREC::GMM ( conf );
           } 
-          else if ( clusterTechnique == "spectral" )
+          else if ( ( clusterTechnique == "spectral" )|| ( clusterTechnique == "SpectralCluster" ) )
           {
             clusterAlgo = new OBJREC::SpectralCluster ( conf );
           }           
@@ -88,7 +88,71 @@ namespace OBJREC {
           }
             
           return clusterAlgo;
+        };
+        
+      static
+      void restoreClusterAlgorithm ( ClusterAlgorithm * _clusterAlgo, std::istream & is, int format = 0 )
+      {
+                
+        if ( is.good() )
+        {
+          if ( _clusterAlgo != NULL )
+            delete _clusterAlgo;
+          
+          
+          std::string className;
+          is >> className; //class name
+                              
+          if ( className == "<KMeans>" )
+          {
+            _clusterAlgo = new OBJREC::KMeans();
+          }
+          else if ( className == "<KMeansHeuristic>" )
+          {
+            _clusterAlgo = new OBJREC::KMeansHeuristic();            
+          }
+          else if ( className == "<KMeansMatlab>" )
+          {
+            _clusterAlgo = new OBJREC::KMeansMatlab();
+          }
+          else if ( className == "<KMedian>" )
+          {
+            _clusterAlgo = new OBJREC::KMedian();
+          }
+          else if ( className == "<GMM>" )
+          {
+            _clusterAlgo = new OBJREC::GMM();
+          } 
+          else if ( className == "<SpectralCluster>" )
+          {          
+            _clusterAlgo = new OBJREC::SpectralCluster();          
+          }
+          else if ( className == "<RandomClustering>" )
+          {          
+            _clusterAlgo = new OBJREC::RandomClustering();          
+          }          
+          else
+          {
+            fthrow ( NICE::Exception, "GenericClusterAlgorithmSelection::restoreClusterAlgo -- class name " << className << "unknown. Aborting." );
+          }
+          
+          //undo reading of class name
+          
+          for ( uint i = 0; i < className.size(); i++)
+          {
+            is.unget();
+          }
+          
+          //now, call the restore method of the underlying object
+          //NOTE this could be also done externally, leaving only the actual instantiation of the derived objects here
+          _clusterAlgo->restore ( is );
+            
         }
+        else
+        {
+          fthrow ( NICE::Exception, "GenericClusterAlgorithmSelection::restoreClusterAlgo -- InStream not initialized - restoring not possible!" );
+        }      
+    };        
   };
 
 }

+ 165 - 10
math/cluster/KMeans.cpp

@@ -26,30 +26,56 @@ using namespace NICE;
 
 #undef DEBUG_KMEANS
 
+///////////////////// ///////////////////// /////////////////////
+//                   CONSTRUCTORS / DESTRUCTORS
+///////////////////// ///////////////////// /////////////////////
+
+KMeans::KMeans() : ClusterAlgorithm() 
+{
+  this->noClusters       = 20;
+  this->distanceType     = "euclidean";
+  this->distancefunction = NULL;
+  this->d_minDelta       = 1e-5;
+  this->i_maxIterations  = 200;
+}
+
 KMeans::KMeans(const int & _noClusters, const std::string & _distanceType) :
         noClusters(_noClusters), distanceType(_distanceType)
 {
     //srand(time(NULL));
     this->distancefunction = GenericDistanceSelection::selectDistance(distanceType);
+    
+  this->d_minDelta       = 1e-5;
+  this->i_maxIterations  = 200;    
 }
 
-KMeans::KMeans( const NICE::Config *conf, const std::string & _section)
+KMeans::KMeans( const NICE::Config * _conf, const std::string & _confSection)
 {       
-  this->distanceType = conf->gS( _section, "distanceType", "euclidean" );
-  this->distancefunction = GenericDistanceSelection::selectDistance(distanceType);
-  
-  this->d_minDelta  = conf->gD( _section, "minDelta", 1e-5 );
-  this->i_maxIterations = conf->gI( _section, "maxIterations", 200);
-  
-  this->noClusters = conf->gI( _section, "noClusters", 20);
-  std::cerr << "KMeans::KMeans -- noClusters: " << this->noClusters << std::endl;
-  
+  this->initFromConfig( _conf, _confSection );
 }
 
 KMeans::~KMeans()
 {
+  if ( this->distancefunction != NULL )
+  {
+    delete this->distancefunction;
+    this->distancefunction = NULL ;
+  }  
+}
+
+void KMeans::initFromConfig( const NICE::Config* _conf, const std::string& _confSection )
+{
+  this->noClusters       = _conf->gI( _confSection, "noClusters", 20);  
+  this->distanceType     = _conf->gS( _confSection, "distanceType", "euclidean" );
+  this->distancefunction = OBJREC::GenericDistanceSelection::selectDistance( this->distanceType );  
+  this->d_minDelta       = _conf->gD( _confSection, "minDelta", 1e-5 );
+  this->i_maxIterations  = _conf->gI( _confSection, "maxIterations", 200);
 }
 
+///////////////////// ///////////////////// /////////////////////
+//                      CLUSTERING STUFF
+///////////////////// ///////////////////// ////////////////// 
+
 void KMeans::initial_guess(const NICE::VVector & features, NICE::VVector & prototypes)
 {
     int j = 0;
@@ -329,3 +355,132 @@ void KMeans::print_iteration(int iterations, NICE::VVector & prototypes, double
         std::cerr << "prototype = " << (*i) << std::endl;
     }
 }
+
+
+///////////////////// INTERFACE PERSISTENT /////////////////////
+// interface specific methods for store and restore
+///////////////////// INTERFACE PERSISTENT ///////////////////// 
+
+void KMeans::restore ( std::istream & is, int format )
+{
+  //delete everything we knew so far...
+  this->clear();
+  
+  
+  if ( is.good() )
+  {
+    
+    std::string tmp;
+    is >> tmp; //class name 
+    
+    if ( ! this->isStartTag( tmp, "KMeans" ) )
+    {
+      std::cerr << " WARNING - attempt to restore KMeans, but start flag " << tmp << " does not match! Aborting... " << std::endl;
+      throw;
+    }   
+    
+    bool b_endOfBlock ( false ) ;
+    
+    while ( !b_endOfBlock )
+    {
+      is >> tmp; // start of block 
+      
+      if ( this->isEndTag( tmp, "KMeans" ) )
+      {
+        b_endOfBlock = true;
+        continue;
+      }      
+      
+      tmp = this->removeStartTag ( tmp );    
+      
+      if ( tmp.compare("noClusters") == 0 )
+      {
+        is >> this->noClusters;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }
+      else if ( tmp.compare("distanceType") == 0 )
+      {
+        is >> this->distanceType;
+        //TODO fixme
+        this->distancefunction = OBJREC::GenericDistanceSelection::selectDistance( this->distanceType );  
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }      
+      else if ( tmp.compare("distancefunction") == 0 )
+      {
+        //TODO is >> this->distancefunction;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }
+      else if ( tmp.compare("d_minDelta") == 0 )
+      {
+        is >> this->d_minDelta;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }      
+      else if ( tmp.compare("i_maxIterations") == 0 )
+      {
+        is >> this->i_maxIterations;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }
+      else
+      {
+      std::cerr << "WARNING -- unexpected KMeans object -- " << tmp << " -- for restoration... aborting" << std::endl;
+      throw;
+      }
+    }
+  }
+  else
+  {
+    std::cerr << "KMeans::restore -- InStream not initialized - restoring not possible!" << std::endl;
+    throw;
+  }
+}
+
+void KMeans::store ( std::ostream & os, int format ) const
+{ 
+  if (os.good())
+  {
+    // show starting point
+    os << this->createStartTag( "KMeans" ) << std::endl;   
+    
+    os << this->createStartTag( "noClusters" ) << std::endl;
+    os << this->noClusters << std::endl;
+    os << this->createEndTag( "noClusters" ) << std::endl;  
+
+    os << this->createStartTag( "distanceType" ) << std::endl;
+    os << this->distanceType << std::endl;
+    os << this->createEndTag( "distanceType" ) << std::endl;
+    
+    os << this->createStartTag( "distancefunction" ) << std::endl;
+    //TODO os << this->distancefunction << std::endl;
+    os << this->createEndTag( "distancefunction" ) << std::endl;  
+
+    os << this->createStartTag( "d_minDelta" ) << std::endl;
+    os << this->d_minDelta << std::endl;
+    os << this->createEndTag( "d_minDelta" ) << std::endl; 
+    
+    os << this->createStartTag( "i_maxIterations" ) << std::endl;
+    os << this->i_maxIterations << std::endl;
+    os << this->createEndTag( "i_maxIterations" ) << std::endl;
+    
+    // done
+    os << this->createEndTag( "KMeans" ) << std::endl;    
+  }
+  else
+  {
+    std::cerr << "OutStream not initialized - storing not possible!" << std::endl;
+  }
+}
+
+void KMeans::clear ()
+{
+  if ( this->distancefunction != NULL )
+  {
+    delete this->distancefunction;
+    this->distancefunction = NULL ;
+  }  
+}
+

+ 145 - 98
math/cluster/KMeans.h

@@ -22,108 +22,155 @@
 namespace OBJREC {
 
 /** K-Means */
-  /**
-   * @class K-Means
-   * @brief K-Means
-   * @author Erik Rodner, Alexander Freytag
-   * @date 29-10-2007 (dd-mm-yyyy)
-  */  
-  class KMeans : 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;
-          
-          //! maximum difference between prototype-solutions of two iterations for convergence
-          double d_minDelta;
-          
-          //! maximum number of iterations until convergence
-          int i_maxIterations;          
-          
-        /************************
-        * 
-        *   protected methods
-        * 
-        **************************/          
-          
-        //! compute the distance between two features using the specified distance metric
-          double vectorDistance(const NICE::Vector &vector1, const NICE::Vector &vector2, uint distancetype);
-          
-        //! compute assignments of all given features wrt to the currently known prototypes (cluster centroids) == ~ 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 the difference between prototypes of previous iteration and those currently found
-          double compute_delta ( const NICE::VVector & oldprototypes,
-                                const NICE::VVector & prototypes );
-
-        //! 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 );
-          
-        //! have an initial guess, i.e., randomly pick some features as initial cluster centroids
-          void initial_guess ( const NICE::VVector & features,
-                              NICE::VVector & prototypes );
-        //! give additional information for the current iteration
-          void print_iteration ( int iterations,
+/**
+  * @class K-Means
+  * @brief K-Means
+  * @author Erik Rodner, Alexander Freytag
+  * @date 29-10-2007 (dd-mm-yyyy)
+*/  
+class KMeans : 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;
+        
+        //! maximum difference between prototype-solutions of two iterations for convergence
+        double d_minDelta;
+        
+        //! maximum number of iterations until convergence
+        int i_maxIterations;          
+        
+      /************************
+      * 
+      *   protected methods
+      * 
+      **************************/          
+        
+      //! compute the distance between two features using the specified distance metric
+        double vectorDistance(const NICE::Vector &vector1, const NICE::Vector &vector2, uint distancetype);
+        
+      //! compute assignments of all given features wrt to the currently known prototypes (cluster centroids) == ~ 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 the difference between prototypes of previous iteration and those currently found
+        double compute_delta ( const NICE::VVector & oldprototypes,
+                              const NICE::VVector & prototypes );
+
+      //! compute (update) prototypes given the current assignments == ~ M-step
+        int compute_prototypes ( const NICE::VVector & features,
                                 NICE::VVector & prototypes,
-                                double delta );
-
-      public:
-
-        /**
-        * @brief simple constructor
-        * @param _noClusters the number of clusters to be computed
-        * @param _distanceMode a string specifying the distance function to be used (default: euclidean)
-        */
-        KMeans( const int & _noClusters , const std::string & _distanceMode="euclidean");
+                                std::vector<double> & weights,
+                                const std::vector<int>    & assignment );
+        
+      //! have an initial guess, i.e., randomly pick some features as initial cluster centroids
+        void initial_guess ( const NICE::VVector & features,
+                            NICE::VVector & prototypes );
+      //! give additional information for the current iteration
+        void print_iteration ( int iterations,
+                              NICE::VVector & prototypes,
+                              double delta );
+
+    public:
       
-        /**
-        * @brief standard constructor
-        * @param conf config file specifying all relevant variable settings
-        * @param _section name of the section within the configfile where the settings can be found (default: KMeans)
-        */
-        KMeans( const NICE::Config *conf, const std::string & _section = "KMeans");      
-
-        /** simple destructor */
-        virtual ~KMeans();
+    ///////////////////// ///////////////////// /////////////////////
+    //                   CONSTRUCTORS / DESTRUCTORS
+    ///////////////////// ///////////////////// ///////////////////// 
+
+    /** 
+     * @brief default constructor
+     * @date 12-02-2014 (dd-mm-yyyy )
+     * @author Alexander Freytag
+     */
+    KMeans ( );        
+
+      /**
+      * @brief simple constructor
+      * @param _noClusters the number of clusters to be computed
+      * @param _distanceMode a string specifying the distance function to be used (default: euclidean)
+      */
+      KMeans( const int & _noClusters , const std::string & _distanceMode="euclidean");
+    
+      /**
+      * @brief standard constructor
+      * @param conf config file specifying all relevant variable settings
+      * @param _section name of the section within the configfile where the settings can be found (default: KMeans)
+      */
+      KMeans( const NICE::Config * _conf, const std::string & _confSection = "KMeans");      
+
+      /** simple destructor */
+      virtual ~KMeans();
+        
+    /** 
+     * @brief Jobs previously performed in the config-version of the constructor, read settings etc.
+     * @author Alexander Freytag
+     * @date 12-02-2014 ( dd-mm-yyyy )
+     */    
+    void initFromConfig ( const NICE::Config * _conf, const std::string & _confSection = "KMeans");     
+    
+    ///////////////////// ///////////////////// /////////////////////
+    //                      CLUSTERING STUFF
+    ///////////////////// ///////////////////// //////////////////         
 
         
-          /**
-          *@brief this is the actual method that performs the clustering for a given set of features
-          *@author Erik Rodner, Alexander Freytag
-          *@date 29-10-2007 (dd-mm-yyyy)
-          *@param   features input features to be clustered
-          *@param   prototypes computed prototypes (cluster medoids) 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 );
+        /**
+        *@brief this is the actual method that performs the clustering for a given set of features
+        *@author Erik Rodner, Alexander Freytag
+        *@date 29-10-2007 (dd-mm-yyyy)
+        *@param   features input features to be clustered
+        *@param   prototypes computed prototypes (cluster medoids) 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 12-02-2014 ( dd-mm-yyyy )
+    */
+    void restore ( std::istream & is, int format = 0 );
+
+    /**
+    * @brief Save object to external file (stream)
+    * @author Alexander Freytag
+    * @date 12-02-2014 ( dd-mm-yyyy )
+    */
+    void store ( std::ostream & os, int format = 0 ) const;
+
+    /**
+    * @brief Clear object
+    * @author Alexander Freytag
+    * @date 12-02-2014 ( dd-mm-yyyy )
+    */
+    void clear ();          
 
   };
 

+ 142 - 8
math/cluster/KMeansHeuristic.cpp

@@ -18,25 +18,52 @@ using namespace NICE;
 
 #undef DEBUG_KMeansHeuristic
 
+
+///////////////////// ///////////////////// /////////////////////
+//                   CONSTRUCTORS / DESTRUCTORS
+///////////////////// ///////////////////// /////////////////////
+
+KMeansHeuristic::KMeansHeuristic() : ClusterAlgorithm()
+{
+  this->noClusters       = 20;
+  this->distanceType     = "euclidean";
+  this->distancefunction = NULL;
+}
+
 KMeansHeuristic::KMeansHeuristic(int _noClusters, string _distanceType) :
-	noClusters(_noClusters), distanceType(_distanceType)
+        noClusters(_noClusters), distanceType(_distanceType)
 {
   //srand(time(NULL));
-  distancefunction = GenericDistanceSelection::selectDistance(distanceType);
+  this->distancefunction = GenericDistanceSelection::selectDistance(distanceType);
 }
 
-KMeansHeuristic::KMeansHeuristic( const NICE::Config *conf, const std::string & _section)
-{       
-  this->distanceType = conf->gS( _section, "distanceType", "euclidean" );
-  this->distancefunction = GenericDistanceSelection::selectDistance(distanceType);
-  
-  this->noClusters = conf->gI( _section, "noClusters", 20);
+KMeansHeuristic::KMeansHeuristic( const NICE::Config * _conf, const std::string & _confSection)
+{  
+  this->initFromConfig( _conf, _confSection );
 }
 
+
 KMeansHeuristic::~KMeansHeuristic()
 {
+  if ( this->distancefunction != NULL )
+  {
+    delete this->distancefunction;
+    this->distancefunction = NULL ;
+  }    
+}
+
+
+void KMeansHeuristic::initFromConfig( const NICE::Config* _conf, const std::string& _confSection )
+{
+  this->noClusters       = _conf->gI( _confSection, "noClusters", 20);
+  this->distanceType     = _conf->gS( _confSection, "distanceType", "euclidean" );
+  this->distancefunction = OBJREC::GenericDistanceSelection::selectDistance( this->distanceType );
 }
 
+///////////////////// ///////////////////// /////////////////////
+//                      CLUSTERING STUFF
+///////////////////// ///////////////////// ////////////////// 
+
 void KMeansHeuristic::initial_guess(const VVector & features,
 		VVector & prototypes)
 {
@@ -321,3 +348,110 @@ void KMeansHeuristic::print_iteration(int iterations, VVector & prototypes,
 		cerr << "prototype = " << (*i) << endl;
 	}
 }
+
+///////////////////// INTERFACE PERSISTENT /////////////////////
+// interface specific methods for store and restore
+///////////////////// INTERFACE PERSISTENT ///////////////////// 
+
+void KMeansHeuristic::restore ( std::istream & is, int format )
+{
+  //delete everything we knew so far...
+  this->clear();
+  
+  
+  if ( is.good() )
+  {
+    
+    std::string tmp;
+    is >> tmp; //class name 
+    
+    if ( ! this->isStartTag( tmp, "KMeansHeuristic" ) )
+    {
+      std::cerr << " WARNING - attempt to restore KMeansHeuristic, but start flag " << tmp << " does not match! Aborting... " << std::endl;
+      throw;
+    }   
+    
+    bool b_endOfBlock ( false ) ;
+    
+    while ( !b_endOfBlock )
+    {
+      is >> tmp; // start of block 
+      
+      if ( this->isEndTag( tmp, "KMeansHeuristic" ) )
+      {
+        b_endOfBlock = true;
+        continue;
+      }      
+      
+      tmp = this->removeStartTag ( tmp );    
+      
+      if ( tmp.compare("noClusters") == 0 )
+      {
+        is >> this->noClusters;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }
+      else if ( tmp.compare("distanceType") == 0 )
+      {
+        is >> this->distanceType;
+        //TODO fixme
+        this->distancefunction = OBJREC::GenericDistanceSelection::selectDistance( this->distanceType );  
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }      
+      else if ( tmp.compare("distancefunction") == 0 )
+      {
+        //TODO is >> this->distancefunction;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }
+      else
+      {
+      std::cerr << "WARNING -- unexpected KMeansHeuristic object -- " << tmp << " -- for restoration... aborting" << std::endl;
+      throw;
+      }
+    }
+  }
+  else
+  {
+    std::cerr << "KMeansHeuristic::restore -- InStream not initialized - restoring not possible!" << std::endl;
+    throw;
+  }
+}
+
+void KMeansHeuristic::store ( std::ostream & os, int format ) const
+{ 
+  if (os.good())
+  {
+    // show starting point
+    os << this->createStartTag( "KMeansHeuristic" ) << std::endl;
+    
+    os << this->createStartTag( "noClusters" ) << std::endl;
+    os << this->noClusters << std::endl;
+    os << this->createEndTag( "noClusters" ) << std::endl;  
+
+    os << this->createStartTag( "distanceType" ) << std::endl;
+    os << this->distanceType << std::endl;
+    os << this->createEndTag( "distanceType" ) << std::endl;
+    
+    os << this->createStartTag( "distancefunction" ) << std::endl;
+    //TODO os << this->distancefunction << std::endl;
+    os << this->createEndTag( "distancefunction" ) << std::endl;  
+    
+    // done
+    os << this->createEndTag( "KMeansHeuristic" ) << std::endl;    
+  }
+  else
+  {
+    std::cerr << "OutStream not initialized - storing not possible!" << std::endl;
+  }
+}
+
+void KMeansHeuristic::clear ()
+{ 
+  if ( this->distancefunction != NULL )
+  {
+    delete this->distancefunction;
+    this->distancefunction = NULL ;
+  }    
+}

+ 69 - 7
math/cluster/KMeansHeuristic.h

@@ -1,7 +1,7 @@
 /** 
  * @file KMeansHeuristic.h
  * @brief K-Means
- * @author Erik Rodner, Michael Koch, Michael Trummer
+ * @author Erik Rodner, Michael Koch, Michael Trummer, Alexander Freytag
  * @date 02/04/2011
 
  */
@@ -10,8 +10,8 @@
 
 #include <core/basics/Config.h>
 #include <core/vector/Distance.h>
-#include "core/vector/VectorT.h"
-#include "core/vector/MatrixT.h"
+#include <core/vector/VectorT.h>
+#include <core/vector/MatrixT.h>
 
 #include "ClusterAlgorithm.h"
 
@@ -19,15 +19,29 @@
 namespace OBJREC
 {
 
-  /** K-Means (but what does Heuristic actually mean? )*/
-  class KMeansHeuristic: public ClusterAlgorithm
-  {
+/** K-Means (but what does Heuristic actually mean? )*/
+class KMeansHeuristic: public ClusterAlgorithm
+{
 
   protected:
+    
+    /************************
+    * 
+    *   protected variables
+    * 
+    **************************/         
     int noClusters;
+    
     std::string distanceType;
+    
     NICE::VectorDistance<double> *distancefunction;
     
+    /************************
+    * 
+    *   protected methods
+    * 
+    **************************/     
+    
     double compute_assignments(const NICE::VVector & features,
         const NICE::VVector & prototypes, std::vector<int> & assignment);
 
@@ -43,7 +57,19 @@ namespace OBJREC
     void print_iteration(int iterations, NICE::VVector & prototypes, double delta);
     int robust_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
+     */
+    KMeansHeuristic ( );         
 
     /** simple constructor */
     KMeansHeuristic(int noClusters, std::string distanceMode = "euclidean");
@@ -55,12 +81,48 @@ namespace OBJREC
     * @date 14-06-2013 (dd-mm-yyyy)
     * @author Alexander Freytag
     */
-    KMeansHeuristic( const NICE::Config *conf, const std::string & _section = "KMeansHeuristic");    
+    KMeansHeuristic( const NICE::Config * _conf, const std::string & _confSection = "KMeansHeuristic");    
 
     /** simple destructor */
     virtual ~KMeansHeuristic();
+    
+    /** 
+     * @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 = "KMeansHeuristic");     
+    
+    ///////////////////// ///////////////////// /////////////////////
+    //                      CLUSTERING STUFF
+    ///////////////////// ///////////////////// //////////////////       
 
     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 ();       
 
   };
 

+ 162 - 8
math/cluster/KMeansMatlab.cpp

@@ -19,17 +19,25 @@ using namespace NICE;
 
 #undef DEBUG_KMeansMatlab
 
-KMeansMatlab::KMeansMatlab( const Config *conf, const std::string & _section )
+///////////////////// ///////////////////// /////////////////////
+//                   CONSTRUCTORS / DESTRUCTORS
+///////////////////// ///////////////////// /////////////////////
+
+KMeansMatlab::KMeansMatlab() : ClusterAlgorithm()
 {
-  this->noClusters = conf->gI( _section, "noClusters", 20);
+  this->noClusters    = 20;
   
-    kmeansDir = conf->gS(_section, "source_root", "/home/rodner/osl/labor/cvs/osl/") + "/kernel/";
-    inputFN   = conf->gS(_section, "tmpInput", "/tmp/KMeansMatlab.input" );
-    outputFN   = conf->gS(_section, "tmpOutput", "/tmp/KMeansMatlab.output" );
+  this->kmeansDir     = "/home/rodner/osl/labor/cvs/osl/kernel/";
+  this->inputFN       = "/tmp/KMeansMatlab.input";
+  this->outputFN      = "/tmp/KMeansMatlab.output" ;
 
-    matlabExec = conf->gS(_section, "matlab_exec", "matlab");
-    matlabArgs = conf->gS(_section, "matlab_args", "-nosplash -nojvm -nodesktop");   
-    
+  this->matlabExec    = "matlab";
+  this->matlabArgs    = "-nosplash -nojvm -nodesktop";   
+}
+
+KMeansMatlab::KMeansMatlab( const NICE::Config * _conf, const std::string & _confSection )
+{
+  this->initFromConfig ( _conf, _confSection );   
 }
 
 KMeansMatlab::~KMeansMatlab()
@@ -38,6 +46,22 @@ KMeansMatlab::~KMeansMatlab()
     pclose (matlabPipe);
 }
 
+void KMeansMatlab::initFromConfig( const NICE::Config* _conf, const std::string& _confSection )
+{
+  this->noClusters   = _conf->gI( _confSection, "noClusters", 20);
+  
+  this->kmeansDir    = _conf->gS(_confSection, "source_root", "/home/rodner/osl/labor/cvs/osl/") + "/kernel/";
+  this->inputFN      = _conf->gS(_confSection, "tmpInput", "/tmp/KMeansMatlab.input" );
+  this->outputFN     = _conf->gS(_confSection, "tmpOutput", "/tmp/KMeansMatlab.output" );
+
+  this->matlabExec   = _conf->gS(_confSection, "matlab_exec", "matlab");
+  this->matlabArgs   = _conf->gS(_confSection, "matlab_args", "-nosplash -nojvm -nodesktop"); 
+}
+
+///////////////////// ///////////////////// /////////////////////
+//                      CLUSTERING STUFF
+///////////////////// ///////////////////// ////////////////// 
+
 
 int KMeansMatlab::compute_prototypes ( const VVector & features,
 				  VVector & prototypes,
@@ -204,3 +228,133 @@ void KMeansMatlab::cluster ( const VVector & features,
 	exit(-1);
     }
 }
+
+///////////////////// INTERFACE PERSISTENT /////////////////////
+// interface specific methods for store and restore
+///////////////////// INTERFACE PERSISTENT ///////////////////// 
+
+void KMeansMatlab::restore ( std::istream & is, int format )
+{
+  //delete everything we knew so far...
+  this->clear();
+  
+  
+  if ( is.good() )
+  {
+    
+    std::string tmp;
+    is >> tmp; //class name 
+    
+    if ( ! this->isStartTag( tmp, "KMeansMatlab" ) )
+    {
+      std::cerr << " WARNING - attempt to restore KMeansMatlab, but start flag " << tmp << " does not match! Aborting... " << std::endl;
+      throw;
+    }   
+    
+    bool b_endOfBlock ( false ) ;
+    
+    while ( !b_endOfBlock )
+    {
+      is >> tmp; // start of block 
+      
+      if ( this->isEndTag( tmp, "KMeansMatlab" ) )
+      {
+        b_endOfBlock = true;
+        continue;
+      }      
+      
+      tmp = this->removeStartTag ( tmp );   
+      
+      if ( tmp.compare("noClusters") == 0 )
+      {
+        is >> this->noClusters;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }
+      else if ( tmp.compare("kmeansDir") == 0 )
+      {
+        is >> this->kmeansDir;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }      
+      else if ( tmp.compare("inputFN") == 0 )
+      {
+        is >> this->inputFN;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }
+      else if ( tmp.compare("outputFN") == 0 )
+      {
+        is >> this->outputFN;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }
+      else if ( tmp.compare("matlabExec") == 0 )
+      {
+        is >> this->matlabExec;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }      
+      else if ( tmp.compare("matlabArgs") == 0 )
+      {
+        is >> this->matlabArgs;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }      
+      else
+      {
+      std::cerr << "WARNING -- unexpected KMeansMatlab object -- " << tmp << " -- for restoration... aborting" << std::endl;
+      throw;
+      }
+    }
+  }
+  else
+  {
+    std::cerr << "KMeansMatlab::restore -- InStream not initialized - restoring not possible!" << std::endl;
+    throw;
+  }
+}
+
+void KMeansMatlab::store ( std::ostream & os, int format ) const
+{ 
+  if (os.good())
+  {
+    // show starting point
+    os << this->createStartTag( "KMeansMatlab" ) << std::endl;
+    
+    os << this->createStartTag( "noClusters" ) << std::endl;
+    os << this->noClusters << std::endl;
+    os << this->createEndTag( "noClusters" ) << std::endl;  
+
+    os << this->createStartTag( "kmeansDir" ) << std::endl;
+    os << this->kmeansDir << std::endl;
+    os << this->createEndTag( "kmeansDir" ) << std::endl;
+    
+    os << this->createStartTag( "inputFN" ) << std::endl;
+    os << this->inputFN << std::endl;
+    os << this->createEndTag( "inputFN" ) << std::endl;  
+
+    os << this->createStartTag( "outputFN" ) << std::endl;
+    os << this->outputFN << std::endl;
+    os << this->createEndTag( "outputFN" ) << std::endl;  
+
+    os << this->createStartTag( "matlabExec" ) << std::endl;
+    os << this->matlabExec << std::endl;
+    os << this->createEndTag( "matlabExec" ) << std::endl;
+    
+    os << this->createStartTag( "matlabArgs" ) << std::endl;
+    os << this->matlabArgs << std::endl;
+    os << this->createEndTag( "matlabArgs" ) << std::endl;  
+    
+    // done
+    os << this->createEndTag( "KMeansMatlab" ) << std::endl;    
+  }
+  else
+  {
+    std::cerr << "OutStream not initialized - storing not possible!" << std::endl;
+  }
+}
+
+void KMeansMatlab::clear ()
+{ 
+}

+ 107 - 48
math/cluster/KMeansMatlab.h

@@ -17,58 +17,117 @@
 
 namespace OBJREC {
 
-  /** 
-  * @class KMeansMatlab
-  * @brief K-Means using a matlab implementation
-  * @author Erik Rodner
-  */
-
-  class KMeansMatlab : public ClusterAlgorithm
-  {
-
-      protected:
-        int noClusters;
-        // refactor-nice.pl: check this substitution
-        // old: string kmeansDir;
-        std::string kmeansDir;
-        // refactor-nice.pl: check this substitution
-        // old: string matlabExec;
-        std::string matlabExec;
-        // refactor-nice.pl: check this substitution
-        // old: string matlabArgs;
-        std::string matlabArgs;
-
-        // refactor-nice.pl: check this substitution
-        // old: string inputFN;
-        std::string inputFN;
-        // refactor-nice.pl: check this substitution
-        // old: string outputFN;
-        std::string outputFN;
-
-        FILE *matlabPipe;
-        
-        int compute_prototypes ( const NICE::VVector & features,
-                NICE::VVector & prototypes,
-                std::vector<double> & weights,
-                const std::vector<int>    & assignment );
+/** 
+* @class KMeansMatlab
+* @brief K-Means using a matlab implementation
+* @author Erik Rodner
+*/
 
+class KMeansMatlab : public ClusterAlgorithm
+{
 
-      public:
+  protected:
+    
+      /************************
+      * 
+      *   protected variables
+      * 
+      **************************/     
+      int noClusters;
+      // refactor-nice.pl: check this substitution
+      // old: string kmeansDir;
+      std::string kmeansDir;
+      // refactor-nice.pl: check this substitution
+      // old: string matlabExec;
+      std::string matlabExec;
+      // refactor-nice.pl: check this substitution
+      // old: string matlabArgs;
+      std::string matlabArgs;
+
+      // refactor-nice.pl: check this substitution
+      // old: string inputFN;
+      std::string inputFN;
+      // refactor-nice.pl: check this substitution
+      // old: string outputFN;
+      std::string outputFN;
+
+      FILE *matlabPipe;
+      
+      /************************
+      * 
+      *   protected methods
+      * 
+      **************************/        
+      
+      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
+     */
+    KMeansMatlab ( );        
     
-        /** 
-        * @brief simple constructor
-        * @author Erik Rodner, Alexander Freytag
-        * Among others, you can specify for "section" the following attributes: "source_root", "tmpInput", "tmpOutput", "matlab_exec", "matlab_args"
-        */
-        KMeansMatlab( const NICE::Config *conf,  const std::string & _section = "KMeansMatlab" );
-            
-        /** simple destructor */
-        virtual ~KMeansMatlab();
+    /** 
+    * @brief simple constructor
+    * @author Erik Rodner, Alexander Freytag
+    * Among others, you can specify for "section" the following attributes: "source_root", "tmpInput", "tmpOutput", "matlab_exec", "matlab_args"
+    */
+    KMeansMatlab( const NICE::Config * _conf,  const std::string & _confSection = "KMeansMatlab" );
+        
+    /** simple destructor */
+    virtual ~KMeansMatlab();
+        
+    /** 
+     * @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 = "KMeansMatlab");         
+        
+    ///////////////////// ///////////////////// /////////////////////
+    //                      CLUSTERING STUFF
+    ///////////////////// ///////////////////// //////////////////         
           
-        void cluster ( const NICE::VVector & features,
-                NICE::VVector & prototypes,
-                std::vector<double> & weights,
-                std::vector<int>    & assignment );
+    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 ();            
 
   };
 

+ 161 - 9
math/cluster/KMedian.cpp

@@ -40,32 +40,57 @@ struct CompareSecond
 #undef DEBUG_KMEDIAN_PROTOCOMP
 // #define DEBUG_KMEDIAN_PROTOCOMP
 
+///////////////////// ///////////////////// /////////////////////
+//                   CONSTRUCTORS / DESTRUCTORS
+///////////////////// ///////////////////// /////////////////////
+
+KMedian::KMedian() : ClusterAlgorithm() 
+{
+  this->noClusters       = 20;
+  this->distanceType     = "euclidean";
+  this->distancefunction = NULL;
+  this->d_minDelta       = 1e-5;
+  this->i_maxIterations  = 200;
+}
+
 
 KMedian::KMedian(const int & _noClusters, const std::string & _distanceType) :
   noClusters(_noClusters), distanceType(_distanceType)
 {
   //srand(time(NULL));
-  distancefunction = GenericDistanceSelection::selectDistance(distanceType);
+  this->distancefunction = GenericDistanceSelection::selectDistance( this->distanceType );
   
   this->d_minDelta  = 1e-5;
   this->i_maxIterations = 200;
 }
 
-KMedian::KMedian( const NICE::Config *conf, const std::string & _section)
+KMedian::KMedian( const NICE::Config * _conf, const std::string & _confSection)
 {       
-  this->distanceType = conf->gS( _section, "distanceType", "euclidean" );
-  this->distancefunction = GenericDistanceSelection::selectDistance(distanceType);
-  
-  this->d_minDelta  = conf->gD( _section, "minDelta", 1e-5 );
-  this->i_maxIterations = conf->gI( _section, "maxIterations", 200);
-  
-  this->noClusters = conf->gI( _section, "noClusters", 20);
+  this->initFromConfig( _conf, _confSection );
 }
 
 KMedian::~KMedian()
 {
+  if ( this->distancefunction != NULL )
+  {
+    delete this->distancefunction;
+    this->distancefunction = NULL ;
+  }
+}
+
+void KMedian::initFromConfig( const NICE::Config* _conf, const std::string& _confSection )
+{
+  this->noClusters       = _conf->gI( _confSection, "noClusters", 20);  
+  this->distanceType     = _conf->gS( _confSection, "distanceType", "euclidean" );
+  this->distancefunction = OBJREC::GenericDistanceSelection::selectDistance( this->distanceType );  
+  this->d_minDelta       = _conf->gD( _confSection, "minDelta", 1e-5 );
+  this->i_maxIterations  = _conf->gI( _confSection, "maxIterations", 200);
 }
 
+///////////////////// ///////////////////// /////////////////////
+//                      CLUSTERING STUFF
+///////////////////// ///////////////////// ////////////////// 
+
 void KMedian::initial_guess(const VVector & features, VVector & prototypes)
 {
   int j = 0;
@@ -428,3 +453,130 @@ void KMedian::print_iteration( int iterations, VVector & prototypes, double delt
     cerr << "prototype = " << (*i) << endl;
   }
 }
+
+///////////////////// INTERFACE PERSISTENT /////////////////////
+// interface specific methods for store and restore
+///////////////////// INTERFACE PERSISTENT ///////////////////// 
+
+void KMedian::restore ( std::istream & is, int format )
+{
+  //delete everything we knew so far...
+  this->clear();
+  
+  
+  if ( is.good() )
+  {
+    
+    std::string tmp;
+    is >> tmp; //class name 
+    
+    if ( ! this->isStartTag( tmp, "KMedian" ) )
+    {
+      std::cerr << " WARNING - attempt to restore KMedian, but start flag " << tmp << " does not match! Aborting... " << std::endl;
+      throw;
+    }   
+    
+    bool b_endOfBlock ( false ) ;
+    
+    while ( !b_endOfBlock )
+    {
+      is >> tmp; // start of block 
+      
+      if ( this->isEndTag( tmp, "KMedian" ) )
+      {
+        b_endOfBlock = true;
+        continue;
+      }      
+      
+      tmp = this->removeStartTag ( tmp );    
+      
+      if ( tmp.compare("noClusters") == 0 )
+      {
+        is >> this->noClusters;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }
+      else if ( tmp.compare("distanceType") == 0 )
+      {
+        is >> this->distanceType;
+        //TODO fixme
+        this->distancefunction = OBJREC::GenericDistanceSelection::selectDistance( this->distanceType );  
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }      
+      else if ( tmp.compare("distancefunction") == 0 )
+      {
+        //TODO is >> this->distancefunction;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }
+      else if ( tmp.compare("d_minDelta") == 0 )
+      {
+        is >> this->d_minDelta;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }      
+      else if ( tmp.compare("i_maxIterations") == 0 )
+      {
+        is >> this->i_maxIterations;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }
+      else
+      {
+      std::cerr << "WARNING -- unexpected KMedian object -- " << tmp << " -- for restoration... aborting" << std::endl;
+      throw;
+      }
+    }
+  }
+  else
+  {
+    std::cerr << "KMedian::restore -- InStream not initialized - restoring not possible!" << std::endl;
+    throw;
+  }
+}
+
+void KMedian::store ( std::ostream & os, int format ) const
+{ 
+  if (os.good())
+  {
+    // show starting point
+    os << this->createStartTag( "KMedian" ) << std::endl;   
+    
+    os << this->createStartTag( "noClusters" ) << std::endl;
+    os << this->noClusters << std::endl;
+    os << this->createEndTag( "noClusters" ) << std::endl;  
+
+    os << this->createStartTag( "distanceType" ) << std::endl;
+    os << this->distanceType << std::endl;
+    os << this->createEndTag( "distanceType" ) << std::endl;
+    
+    os << this->createStartTag( "distancefunction" ) << std::endl;
+    //TODO os << this->distancefunction << std::endl;
+    os << this->createEndTag( "distancefunction" ) << std::endl;  
+
+    os << this->createStartTag( "d_minDelta" ) << std::endl;
+    os << this->d_minDelta << std::endl;
+    os << this->createEndTag( "d_minDelta" ) << std::endl; 
+    
+    os << this->createStartTag( "i_maxIterations" ) << std::endl;
+    os << this->i_maxIterations << std::endl;
+    os << this->createEndTag( "i_maxIterations" ) << std::endl;
+    
+    // done
+    os << this->createEndTag( "KMedian" ) << std::endl;    
+  }
+  else
+  {
+    std::cerr << "OutStream not initialized - storing not possible!" << std::endl;
+  }
+}
+
+void KMedian::clear ()
+{
+  if ( this->distancefunction != NULL )
+  {
+    delete this->distancefunction;
+    this->distancefunction = NULL ;
+  }  
+}

+ 139 - 92
math/cluster/KMedian.h

@@ -17,111 +17,158 @@
 
 namespace OBJREC {
 
-  /**
-   * @class KMedian
-   * @brief KMedian (aka K-medoid)
-   * @author Alexander Freytag
-   * @date 23-04-2013 (dd-mm-yyyy)
-  */    
-  class KMedian : public ClusterAlgorithm
-  {
-
-      protected:
-        
-      /************************
-       * 
-       *   protected variables
-       * 
-       **************************/ 
+/**
+  * @class KMedian
+  * @brief KMedian (aka K-medoid)
+  * @author Alexander Freytag
+  * @date 23-04-2013 (dd-mm-yyyy)
+*/    
+class KMedian : public ClusterAlgorithm
+{
+
+    protected:
       
-        //! 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;
-        
-        //! maximum difference between prototype-solutions of two iterations for convergence
-        double d_minDelta;
-        
-        //! maximum number of iterations until convergence
-        int i_maxIterations;
-        
-  
-       /************************
-       * 
-       *   protected methods
-       * 
-       **************************/  
+    /************************
+      * 
+      *   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;
+      
+      //! maximum difference between prototype-solutions of two iterations for convergence
+      double d_minDelta;
+      
+      //! maximum number of iterations until convergence
+      int i_maxIterations;
       
-        //! compute the distance between two features using the specified distance metric
-        double vectorDistance(const NICE::Vector &vector1, const NICE::Vector &vector2, uint distancetype);
-        
-        //! 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 );
+      /************************
+      * 
+      *   protected methods
+      * 
+      **************************/  
+    
+      //! compute the distance between two features using the specified distance metric
+      double vectorDistance(const NICE::Vector &vector1, const NICE::Vector &vector2, uint distancetype);
+      
+      //! 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 the difference between prototypes of previous iteration and those currently found
-        double compute_delta ( const NICE::VVector & oldprototypes,
-                    const NICE::VVector & prototypes );
+      //! compute the difference between prototypes of previous iteration and those currently found
+      double compute_delta ( const NICE::VVector & oldprototypes,
+                  const NICE::VVector & prototypes );
+
+      //! 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 );
 
-        //! compute (update) prototypes given the current assignments == ~ M-step
-        int compute_prototypes ( const NICE::VVector & features,
+      //! have an initial guess, i.e., randomly pick some features as initial cluster centroids
+      void initial_guess ( const NICE::VVector & features,
+              NICE::VVector & prototypes );
+      
+      //! give additional information for the current iteration
+      void print_iteration ( int iterations, 
                 NICE::VVector & prototypes,
-                std::vector<double> & weights,
-                const std::vector<int>    & assignment );
+                double delta );
 
-        //! have an initial guess, i.e., randomly pick some features as initial cluster centroids
-        void initial_guess ( const NICE::VVector & features,
-                NICE::VVector & prototypes );
+  public:
         
-        //! give additional information for the current iteration
-        void print_iteration ( int iterations, 
-                  NICE::VVector & prototypes,
-                  double delta );
+    ///////////////////// ///////////////////// /////////////////////
+    //                   CONSTRUCTORS / DESTRUCTORS
+    ///////////////////// ///////////////////// ///////////////////// 
 
-      public:
+    /** 
+     * @brief default constructor
+     * @date 12-02-2014 (dd-mm-yyyy )
+     * @author Alexander Freytag
+     */
+    KMedian ( );    
     
-        /**
-        * @brief simple constructor
-        * @param _noClusters the number of clusters to be computed
-        * @param _distanceMode a string specifying the distance function to be used (default: euclidean)
-        */
-        KMedian( const int & _noClusters , const std::string & _distanceMode="euclidean");
-        
-        /**
-        * @brief standard constructor
-        * @param conf config file specifying all relevant variable settings
-        * @param _section name of the section within the configfile where the settings can be found (default: KMedian)
-        */
-        KMedian( const NICE::Config *conf, const std::string & _section = "KMedian");
+    /**
+    * @brief simple constructor
+    * @param _noClusters the number of clusters to be computed
+    * @param _distanceMode a string specifying the distance function to be used (default: euclidean)
+    */
+    KMedian( const int & _noClusters , const std::string & _distanceMode="euclidean");
+    
+    /**
+    * @brief standard constructor
+    * @param conf config file specifying all relevant variable settings
+    * @param _section name of the section within the configfile where the settings can be found (default: KMedian)
+    */
+    KMedian( const NICE::Config * _conf, const std::string & _confSection = "KMedian");
 
+    
         
-            
-        /** simple destructor */
-        virtual ~KMedian();
-          
-        /**
-        *@brief this is the actual method that performs the clustering for a given set of features
-        *@author Alexander Freytag
-        *@date 25-04-2013 (dd-mm-yyyy)
-        *@param   features input features to be clustered
-        *@param   prototypes computed prototypes (cluster medoids) 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,
+    /** simple destructor */
+    virtual ~KMedian();
+    
+    /** 
+     * @brief Jobs previously performed in the config-version of the constructor, read settings etc.
+     * @author Alexander Freytag
+     * @date 12-02-2014 ( dd-mm-yyyy )
+     */    
+    void initFromConfig ( const NICE::Config * _conf, const std::string & _confSection = "KMedian");     
+    
+    ///////////////////// ///////////////////// /////////////////////
+    //                      CLUSTERING STUFF
+    ///////////////////// ///////////////////// //////////////////       
+      
+    /**
+    *@brief this is the actual method that performs the clustering for a given set of features
+    *@author Alexander Freytag
+    *@date 25-04-2013 (dd-mm-yyyy)
+    *@param   features input features to be clustered
+    *@param   prototypes computed prototypes (cluster medoids) 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 12-02-2014 ( dd-mm-yyyy )
+    */
+    void restore ( std::istream & is, int format = 0 );
+
+    /**
+    * @brief Save object to external file (stream)
+    * @author Alexander Freytag
+    * @date 12-02-2014 ( dd-mm-yyyy )
+    */
+    void store ( std::ostream & os, int format = 0 ) const;
+
+    /**
+    * @brief Clear object
+    * @author Alexander Freytag
+    * @date 12-02-2014 ( dd-mm-yyyy )
+    */
+    void clear ();       
 
   };
 

+ 131 - 6
math/cluster/RandomClustering.cpp

@@ -25,25 +25,42 @@ using namespace std;
 using namespace NICE;
 
 
+///////////////////// ///////////////////// /////////////////////
+//                   CONSTRUCTORS / DESTRUCTORS
+///////////////////// ///////////////////// /////////////////////
+
+RandomClustering::RandomClustering() : ClusterAlgorithm()
+{
+  this->noClusters       = 20;
+  this->distanceType     = "euclidean";
+  this->distancefunction = NULL;
+}
 
 RandomClustering::RandomClustering(const int & _noClusters, const std::string & _distanceType) :
   noClusters(_noClusters), distanceType(_distanceType)
 {
 }
 
-RandomClustering::RandomClustering( const NICE::Config *conf, const std::string & _section)
+RandomClustering::RandomClustering( const NICE::Config * _conf, const std::string & _confSection)
 {  
-  this->noClusters = conf->gI( _section, "noClusters", 20);
-  std::cerr << "RandomClustering::RandomClustering -- noClusters: " << this->noClusters << std::endl;
-  
-  this->distanceType = conf->gS( _section, "distanceType", "euclidean" );
-  this->distancefunction = GenericDistanceSelection::selectDistance(distanceType);  
+  this->initFromConfig ( _conf, _confSection );
 }
 
 RandomClustering::~RandomClustering()
 {
 }
 
+void RandomClustering::initFromConfig( const NICE::Config* _conf, const std::string& _confSection )
+{
+  this->noClusters       = _conf->gI( _confSection, "noClusters", 20);
+  this->distanceType     = _conf->gS( _confSection, "distanceType", "euclidean" );
+  this->distancefunction = OBJREC::GenericDistanceSelection::selectDistance( this->distanceType );
+}
+
+///////////////////// ///////////////////// /////////////////////
+//                      CLUSTERING STUFF
+///////////////////// ///////////////////// ////////////////// 
+
 int RandomClustering::compute_prototypes(const NICE::VVector & _features, NICE::VVector & _prototypes,
     std::vector<double> & _weights, const std::vector<int> & _assignment)
 {
@@ -156,3 +173,111 @@ void RandomClustering::cluster(const NICE::VVector & _features,
   //compute corresponding weights
   this->compute_weights( _features, _weights, _assignment );
 }
+
+
+///////////////////// INTERFACE PERSISTENT /////////////////////
+// interface specific methods for store and restore
+///////////////////// INTERFACE PERSISTENT ///////////////////// 
+
+void RandomClustering::restore ( std::istream & is, int format )
+{
+  //delete everything we knew so far...
+  this->clear();
+  
+  
+  if ( is.good() )
+  {
+    
+    std::string tmp;
+    is >> tmp; //class name 
+    
+    if ( ! this->isStartTag( tmp, "RandomClustering" ) )
+    {
+      std::cerr << " WARNING - attempt to restore RandomClustering, but start flag " << tmp << " does not match! Aborting... " << std::endl;
+      throw;
+    }   
+    
+    bool b_endOfBlock ( false ) ;
+    
+    while ( !b_endOfBlock )
+    {
+      is >> tmp; // start of block 
+      
+      if ( this->isEndTag( tmp, "RandomClustering" ) )
+      {
+        b_endOfBlock = true;
+        continue;
+      }      
+      
+      tmp = this->removeStartTag ( tmp );    
+      
+      if ( tmp.compare("noClusters") == 0 )
+      {
+        is >> this->noClusters;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }
+      else if ( tmp.compare("distanceType") == 0 )
+      {
+        is >> this->distanceType;
+        //TODO fixme
+        this->distancefunction = OBJREC::GenericDistanceSelection::selectDistance( this->distanceType );  
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }      
+      else if ( tmp.compare("distancefunction") == 0 )
+      {
+        //TODO is >> this->distancefunction;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }
+      else
+      {
+      std::cerr << "WARNING -- unexpected RandomClustering object -- " << tmp << " -- for restoration... aborting" << std::endl;
+      throw;
+      }
+    }
+  }
+  else
+  {
+    std::cerr << "RandomClustering::restore -- InStream not initialized - restoring not possible!" << std::endl;
+    throw;
+  }
+}
+
+void RandomClustering::store ( std::ostream & os, int format ) const
+{ 
+  if (os.good())
+  {
+    // show starting point
+    os << this->createStartTag( "RandomClustering" ) << std::endl;
+    
+    os << this->createStartTag( "noClusters" ) << std::endl;
+    os << this->noClusters << std::endl;
+    os << this->createEndTag( "noClusters" ) << std::endl;  
+
+    os << this->createStartTag( "distanceType" ) << std::endl;
+    os << this->distanceType << std::endl;
+    os << this->createEndTag( "distanceType" ) << std::endl;
+    
+    os << this->createStartTag( "distancefunction" ) << std::endl;
+    //TODO os << this->distancefunction << std::endl;
+    os << this->createEndTag( "distancefunction" ) << std::endl;  
+    
+    // done
+    os << this->createEndTag( "RandomClustering" ) << std::endl;    
+  }
+  else
+  {
+    std::cerr << "OutStream not initialized - storing not possible!" << std::endl;
+  }
+}
+
+void RandomClustering::clear ()
+{ 
+  if ( this->distancefunction != NULL )
+  {
+    delete this->distancefunction;
+    this->distancefunction = NULL ;
+  }    
+}

+ 125 - 78
math/cluster/RandomClustering.h

@@ -16,95 +16,142 @@
 
 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
-       * 
-       **************************/ 
+/**
+  * @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:
       
-        //! 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
-       * 
-       **************************/  
+    /************************
+      * 
+      *   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;        
       
-        
-        //! 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,
+      /************************
+      * 
+      *   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,
-              std::vector<int>    & assignment );
+              const std::vector<int>    & assignment );
 
+  public:
+    
+    ///////////////////// ///////////////////// /////////////////////
+    //                   CONSTRUCTORS / DESTRUCTORS
+    ///////////////////// ///////////////////// /////////////////////    
+    
+    /** 
+     * @brief default constructor
+     * @date 13-02-2014 (dd-mm-yyyy )
+     * @author Alexander Freytag
+     */
+    RandomClustering ( );      
 
-        //! 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 );
+    /**
+    * @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");
 
-      public:
     
-        /**
-        * @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 & _section = "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");         
         
-            
-        /** simple destructor */
-        virtual ~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 );
-
-  };
+    /**
+    * @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

+ 124 - 4
math/cluster/SpectralCluster.cpp

@@ -1,7 +1,7 @@
 /** 
 * @file SpectralCluster.cpp
 * @brief spectral clustering by kmeans-clustering of eigenvectors
-* @author Erik Rodner
+* @author Erik Rodner, Alexander Freytag
 * @date 11/13/2007
 
 */
@@ -18,21 +18,42 @@ using namespace OBJREC;
 using namespace std;
 using namespace NICE;
 
+///////////////////// ///////////////////// /////////////////////
+//                   CONSTRUCTORS / DESTRUCTORS
+///////////////////// ///////////////////// /////////////////////
+
+SpectralCluster::SpectralCluster() : ClusterAlgorithm() , kmeans()
+{
+  this->noClusters  = 20;
+  this->alpha       = 1.0;
+}
+
 SpectralCluster::SpectralCluster ( int _noClusters, double alpha ) : noClusters(_noClusters), kmeans(_noClusters)
 {
     this->alpha = alpha;
 }
 
-SpectralCluster::SpectralCluster( const NICE::Config *conf, const std::string & _section) : kmeans(conf)
+SpectralCluster::SpectralCluster( const NICE::Config * _conf, const std::string & _confSection)
 {  
-  this->noClusters = conf->gI( _section, "noClusters", 20);
-  this->alpha = conf->gD( _section, "alpha", 1.0);
+  this->initFromConfig( _conf, _confSection );
 }
 
 SpectralCluster::~SpectralCluster()
 {
 }
 
+void SpectralCluster::initFromConfig( const NICE::Config* _conf, const std::string& _confSection )
+{
+  this->noClusters = _conf->gI( _confSection, "noClusters", 20);
+  this->alpha      = _conf->gD( _confSection, "alpha", 1.0);
+  
+  this->kmeans.initFromConfig( _conf );
+}
+
+///////////////////// ///////////////////// /////////////////////
+//                      CLUSTERING STUFF
+///////////////////// ///////////////////// ////////////////// 
+
 void SpectralCluster::getSimilarityMatrix ( const VVector & features, 
                                             NICE::Matrix & laplacian,
                                             double alpha )
@@ -230,3 +251,102 @@ void SpectralCluster::cluster ( const NICE::VVector & features,
     }
 }
 
+///////////////////// INTERFACE PERSISTENT /////////////////////
+// interface specific methods for store and restore
+///////////////////// INTERFACE PERSISTENT ///////////////////// 
+
+void SpectralCluster::restore ( std::istream & is, int format )
+{
+  //delete everything we knew so far...
+  this->clear();
+  
+  
+  if ( is.good() )
+  {
+    
+    std::string tmp;
+    is >> tmp; //class name 
+    
+    if ( ! this->isStartTag( tmp, "SpectralCluster" ) )
+    {
+      std::cerr << " WARNING - attempt to restore SpectralCluster, but start flag " << tmp << " does not match! Aborting... " << std::endl;
+      throw;
+    }   
+    
+    bool b_endOfBlock ( false ) ;
+    
+    while ( !b_endOfBlock )
+    {
+      is >> tmp; // start of block 
+      
+      if ( this->isEndTag( tmp, "SpectralCluster" ) )
+      {
+        b_endOfBlock = true;
+        continue;
+      }      
+      
+      tmp = this->removeStartTag ( tmp );    
+      
+      if ( tmp.compare("noClusters") == 0 )
+      {
+        is >> this->noClusters;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }          
+      else if ( tmp.compare("alpha") == 0 )
+      {
+        is >> this->alpha;
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }      
+      else if ( tmp.compare("kmeans") == 0 )
+      {
+        this->kmeans.restore ( is );
+        is >> tmp; // end of block 
+        tmp = this->removeEndTag ( tmp );
+      }
+      else
+      {
+      std::cerr << "WARNING -- unexpected SpectralCluster object -- " << tmp << " -- for restoration... aborting" << std::endl;
+      throw;
+      }
+    }
+  }
+  else
+  {
+    std::cerr << "SpectralCluster::restore -- InStream not initialized - restoring not possible!" << std::endl;
+    throw;
+  }
+}
+
+void SpectralCluster::store ( std::ostream & os, int format ) const
+{ 
+  if (os.good())
+  {
+    // show starting point
+    os << this->createStartTag( "SpectralCluster" ) << std::endl;
+    
+    os << this->createStartTag( "noClusters" ) << std::endl;
+    os << this->noClusters << std::endl;
+    os << this->createEndTag( "noClusters" ) << std::endl;  
+
+    os << this->createStartTag( "alpha" ) << std::endl;
+    os << this->alpha << std::endl;
+    os << this->createEndTag( "alpha" ) << std::endl;
+    
+    os << this->createStartTag( "kmeans" ) << std::endl;
+    this->kmeans.store ( os );
+    os << this->createEndTag( "kmeans" ) << std::endl; 
+    
+    // done
+    os << this->createEndTag( "SpectralCluster" ) << std::endl;    
+  }
+  else
+  {
+    std::cerr << "OutStream not initialized - storing not possible!" << std::endl;
+  }
+}
+
+void SpectralCluster::clear ()
+{ 
+}

+ 90 - 42
math/cluster/SpectralCluster.h

@@ -1,7 +1,7 @@
 /** 
 * @file SpectralCluster.h
 * @brief spectral clustering by kmeans-clustering of eigenvectors
-* @author Erik Rodner
+* @author Erik Rodner, Alexander Freytag
 * @date 11/13/2007
 
 */
@@ -17,49 +17,97 @@
 
 namespace OBJREC {
 
-  /** spectral clustering by kmeans-clustering of eigenvectors */
-  class SpectralCluster : public ClusterAlgorithm
-  {
-
-      protected:
-        int noClusters;
-        double alpha;
-
-        KMeans kmeans;
-
-        enum {
-            L_UNNORMALIZED  = 0,
-            L_RW_NORMALIZED 
-        };
-
-        virtual void computeLaplacian ( const NICE::VVector & features,
-                NICE::Matrix & laplacian,
-                int method, double alpha );
-
-
-        virtual void getSimilarityMatrix ( const NICE::VVector & features, 
-                    NICE::Matrix & laplacian, double alpha );
-      public:
+/** spectral clustering by kmeans-clustering of eigenvectors */
+class SpectralCluster : public ClusterAlgorithm
+{
+
+  protected:
+      int noClusters;
+      double alpha;
+
+      KMeans kmeans;
+
+      enum {
+          L_UNNORMALIZED  = 0,
+          L_RW_NORMALIZED 
+      };
+
+      virtual void computeLaplacian ( const NICE::VVector & features,
+              NICE::Matrix & laplacian,
+              int method, double alpha );
+
+
+      virtual void getSimilarityMatrix ( const NICE::VVector & features, 
+                  NICE::Matrix & laplacian, double alpha );
+  public:
+      
+    ///////////////////// ///////////////////// /////////////////////
+    //                   CONSTRUCTORS / DESTRUCTORS
+    ///////////////////// ///////////////////// ///////////////////// 
+
+    /** 
+     * @brief default constructor
+     * @date 12-02-2014 (dd-mm-yyyy )
+     * @author Alexander Freytag
+     */
+    SpectralCluster ( );       
+  
+    /** simple constructor */
+    SpectralCluster (int _noClusters, double alpha);
+    
+    /**
+    * @brief standard constructor
+    * @param conf config file specifying all relevant variable settings
+    * @param _section name of the section within the configfile where the settings can be found (default: SpectralCluster)
+    * @date 14-06-2013 (dd-mm-yyyy)
+    * @author Alexander Freytag
+    */
+    SpectralCluster( const NICE::Config *conf, const std::string & _section = "SpectralCluster");     
+        
+    /** simple destructor */
+    virtual ~SpectralCluster();
+      
+    /** 
+     * @brief Jobs previously performed in the config-version of the constructor, read settings etc.
+     * @author Alexander Freytag
+     * @date 12-02-2014 ( dd-mm-yyyy )
+     */    
+    void initFromConfig ( const NICE::Config * _conf, const std::string & _confSection = "SpectralCluster");     
     
-        /** simple constructor */
-        SpectralCluster (int _noClusters, double alpha);
+    ///////////////////// ///////////////////// /////////////////////
+    //                      CLUSTERING STUFF
+    ///////////////////// ///////////////////// //////////////////       
         
-        /**
-        * @brief standard constructor
-        * @param conf config file specifying all relevant variable settings
-        * @param _section name of the section within the configfile where the settings can be found (default: SpectralCluster)
-        * @date 14-06-2013 (dd-mm-yyyy)
-        * @author Alexander Freytag
-        */
-        SpectralCluster( const NICE::Config *conf, const std::string & _section = "SpectralCluster");     
-            
-        /** simple destructor */
-        virtual ~SpectralCluster();
-          
-        void cluster ( const NICE::VVector & features,
-                NICE::VVector & prototypes,
-                std::vector<double> & weights,
-                std::vector<int>    & assignment );
+    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 12-02-2014 ( dd-mm-yyyy )
+    */
+    void restore ( std::istream & is, int format = 0 );
+
+    /**
+    * @brief Save object to external file (stream)
+    * @author Alexander Freytag
+    * @date 12-02-2014 ( dd-mm-yyyy )
+    */
+    void store ( std::ostream & os, int format = 0 ) const;
+
+    /**
+    * @brief Clear object
+    * @author Alexander Freytag
+    * @date 12-02-2014 ( dd-mm-yyyy )
+    */
+    void clear ();           
 
   };
 

+ 90 - 0
math/cluster/tests/TestGenericClusterAlgorithmSelectionPersistent.cpp

@@ -0,0 +1,90 @@
+/** 
+ * @file TestGenericClusterAlgoSelectionPersistent.cpp
+ * @brief CppUnit-Testcase to create a ClusterAlgoRepresentation object via GenericClusterAlgoSelection, to store it, and to restore it again.
+ * @author Alexander Freytag
+ * @date 12-02-2014 ( dd-mm-yyyy )
+*/
+
+#ifdef NICE_USELIB_CPPUNIT
+
+// STL includes
+
+// NICE-core includes
+
+// gp-hik-core includes
+
+#include "TestGenericClusterAlgorithmSelectionPersistent.h"
+
+using namespace std; //C basics
+using namespace NICE;  // nice-core
+
+const bool verboseStartEnd = true;
+const bool verbose = true;
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION( TestGenericClusterAlgoSelectionPersistent );
+
+void TestGenericClusterAlgoSelectionPersistent::setUp() {
+}
+
+void TestGenericClusterAlgoSelectionPersistent::tearDown() {
+}
+void TestGenericClusterAlgoSelectionPersistent::testPersistentMethods()
+{
+  
+  if (verboseStartEnd)
+    std::cerr << "================== TestGenericClusterAlgoSelectionPersistent::testPersistentMethods ===================== " << std::endl;  
+  
+  NICE::Config conf;
+  conf.sS( "GenericClusterAlgoSelection", "clusterTechnique", "KMeans" );
+  OBJREC::ClusterAlgorithm  * cluster;  
+  
+  cluster = OBJREC::GenericClusterAlgorithmSelection::selectClusterAlgorithm ( &conf, "GenericClusterAlgoSelection");
+  
+  // TEST STORING ABILITIES
+  if ( verbose )
+    std::cerr << " TEST STORING ABILITIES FOR STANDARD LOCALFEATURE" << std::endl;
+  
+  std::string s_destination_save ( "myClusterAlgoSelection.txt" );
+  
+  std::filebuf fbOut;
+  fbOut.open ( s_destination_save.c_str(), ios::out );
+  std::ostream os (&fbOut);
+  //
+  cluster->store( os );
+  //   
+  fbOut.close();
+  
+  // TEST RESTORING ABILITIES
+  if ( verbose )
+    std::cerr << " TEST RESTORING ABILITIES FOR STANDARD LOCALFEATURE" << std::endl;
+    
+  OBJREC::ClusterAlgorithm * clusterRestore = NULL;  
+      
+  std::string s_destination_load ( "myClusterAlgoSelection.txt" );
+  
+  std::filebuf fbIn;
+  fbIn.open ( s_destination_load.c_str(), ios::in );
+  std::istream is (&fbIn);
+  //
+  OBJREC::GenericClusterAlgorithmSelection::restoreClusterAlgorithm ( clusterRestore, is );
+  //   
+  fbIn.close(); 
+  
+  // currently, we have no possibility to actually verify that the restore-operation was successfull, i.e.,
+  // it returned an object identical to the stored one.
+  // However, if we reached this point, at least something went right, so we should be happy...
+
+  // final clean up -- don't waste memory
+  if ( cluster != NULL )
+    delete cluster;
+    
+  if ( clusterRestore != NULL )
+    delete clusterRestore;
+  
+  if (verboseStartEnd)
+    std::cerr << "================== TestGenericClusterAlgoSelectionPersistent::testPersistentMethods done ===================== " << std::endl;  
+  
+}
+
+#endif

+ 31 - 0
math/cluster/tests/TestGenericClusterAlgorithmSelectionPersistent.h

@@ -0,0 +1,31 @@
+#ifndef _TESTGENERICCLUSTERALGOSELECTIONPERSISTENT_H
+#define _TESTGENERICCLUSTERALGOSELECTIONPERSISTENT_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+#include <vislearning/math/cluster/GenericClusterAlgorithmSelection.h>
+
+/**
+ * CppUnit-Testcase. 
+ * @brief CppUnit-Testcase to create a ClutserAlgo object via GenericClusterAlgoSelection, to store it, and to restore it again.
+ * @author Alexander Freytag
+ * @date 13-02-2014 ( dd-mm-yyyy )
+ */
+class TestGenericClusterAlgoSelectionPersistent : public CppUnit::TestFixture {
+
+    CPPUNIT_TEST_SUITE( TestGenericClusterAlgoSelectionPersistent );
+         CPPUNIT_TEST(testPersistentMethods);
+      
+    CPPUNIT_TEST_SUITE_END();
+  
+ private:
+ 
+ public:
+    void setUp();
+    void tearDown();
+
+
+    void testPersistentMethods();
+};
+
+#endif // _TESTGENERICCLUSTERALGOSELECTIONPERSISTENT_H

+ 56 - 0
math/cluster/tests/TestKMedian.cpp

@@ -86,4 +86,60 @@ void TestKMedian::testKMedianClustering()
 }
 
 
+void TestKMedian::testKMedianPersistent() 
+{
+  if (verboseStartEnd)
+    std::cerr << "================== TestKMedian::testKMedianPersistent ===================== " << std::endl;
+  
+  Config * conf = new Config;
+  std::string section ( "KMedian" );
+  conf->sS( section, "distanceType", "euclidean" );
+  conf->sI( section, "maxIterations", 200 );
+  conf->sI( section, "noClusters", 2 );
+   
+  OBJREC::KMedian kMedian;
+  kMedian.initFromConfig( conf, section );
+  
+  // TEST STORING ABILITIES
+  if ( verbose )
+    std::cerr << " TEST STORING ABILITIES FOR KMEDIAN" << std::endl;
+  
+  std::string s_destination_save ( "myKMedian.txt" );
+  
+  std::filebuf fbOut;
+  fbOut.open ( s_destination_save.c_str(), ios::out );
+  std::ostream os (&fbOut);
+  //
+  kMedian.store( os );
+  //   
+  fbOut.close();
+  
+  // TEST RESTORING ABILITIES
+  if ( verbose )
+    std::cerr << " TEST RESTORING ABILITIES FOR KMEDIAN" << std::endl;
+    
+  OBJREC::KMedian kMedianRestore;  
+      
+  std::string s_destination_load ( "myKMedian.txt" );
+  
+  std::filebuf fbIn;
+  fbIn.open ( s_destination_load.c_str(), ios::in );
+  std::istream is (&fbIn);
+  //
+  kMedianRestore.restore( is );
+  //   
+  fbIn.close(); 
+  
+  // currently, we have no possibility to actually verify that the restore-operation was successfull, i.e.,
+  // it returned an object identical to the stored one.
+  // However, if we reached this point, at least something went right, so we should be happy...  
+  
+  //don't waste memory
+  delete conf;
+  
+  if (verboseStartEnd)
+    std::cerr << "================== TestKMedian::testKMedianPersistent done ===================== " << std::endl;
+}
+
+
 #endif

+ 4 - 0
math/cluster/tests/TestKMedian.h

@@ -14,6 +14,8 @@ class TestKMedian : public CppUnit::TestFixture {
     
     CPPUNIT_TEST(testKMedianClustering);
     
+    CPPUNIT_TEST(testKMedianPersistent);
+    
     CPPUNIT_TEST_SUITE_END();
   
  private:
@@ -26,6 +28,8 @@ class TestKMedian : public CppUnit::TestFixture {
     * Constructor / Destructor testing 
     */  
     void testKMedianClustering();
+    
+    void testKMedianPersistent();
 
 };