/*
    Copyright (C) 2012 Bartosz Broda, Jacek Bochenek, Łukasz Biłeńkij, 
    Damian Jaworski, Wojciech Mazur, Dominik Piasecki, Maciej Piasecki, 
    Radosław Ramocki
    
    This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option)
any later version.

    This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. 

    See the LICENSE and COPYING files for more details.
*/

#ifndef K_MEDOIDS_H
#define K_MEDOIDS_H

#include "comparator_all.h"
#include "matrices_all.h"
#include <boost/shared_ptr.hpp>

namespace clustering
{
	namespace kmedoids
	{
		/**
		  * Struct describing cluster member. It contains index of row identifying member and similarity to medoid
		  */
		struct ClusterMember
		{
			size_t row_index;
			double similarity;

			ClusterMember(size_t in, double sim):row_index(in), similarity(sim)
			{}
		};

		typedef std::map<size_t, std::vector<ClusterMember> > ClusterMap;
		typedef std::map<std::pair<size_t, size_t>, double> SimilarityMap;

		/**
		  * Implementation of kmedoids clustering algotithm.
		  */
		class Kmedoids
		{
		public:
			/**
			  * Constructor. It requires number of medoids, shared pointer to SuperMatrix, shared pointer to Compare Function, seed number
			  */
			Kmedoids(size_t medoids_no, Matrices::SuperMatrixPtr matrix, smartcomparator::compare::CompareFunctionPtr cmp_fun, size_t seed);

			/**
			  * Starts clustering process.
			  */
			void StartClustering();

			/**
			  * Returns number of clusters
			  */
			size_t GetClusterNumber(size_t row) const;

			/**
			  * Returns number of rows in matrix
			  */
			size_t GetRows() const;

		private:

			/**
			  * Normalizes matrix
			  */
			void NormalizeMatrix();

			/**
			  * Inits medoids indices vector. It uses random generator with predefined seed.
			  */
			void InitMedoids();

			/**
			  * Builds map of clusters and their members and invokes CountSquareErrors for each cluster
			  */
			double CountSimilarity(const std::vector<size_t> & medoids);

			/**
			  * Counts square errors for each cluster and returns sum of them
			  */
			double CountSquareErrors(ClusterMap & clusters);

			void PrintVector(std::vector<size_t> & v);

			//fields

			/**
			  * Seed used to random numbers generation
			  */
			size_t _seed;

			/**
			  * Number of medoids
			  */
			size_t _medoids_no;

			/**
			  * Vector containing indices of medoids rows
			  */
			std::vector<size_t> _medoids_indices;

			/**
			  * Number of rows in SuperMatrix object
			  */
			size_t _rows;

			/**
			  * Vector containing information whether row is medoid or not
			  */
			std::vector<bool> _isMedoid;

			/**
			  * Shared pointer to SuperMatrix object
			  */
			Matrices::SuperMatrixPtr _matrix;

			/**
			  * Shared pointer to CompareFunction boject
			  */
			smartcomparator::compare::CompareFunctionPtr _cmp_function;

			/**
			  * Map containing similarities between rows in SuperMatrix
			  */
			SimilarityMap _simMatrix;
		};
	}
}

#endif //K_MEDOIDS_H
