/*
    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 EVALUATOR_H
#define EVALUATOR_H

#include "clustering_all.h"
#include "matrices_all.h"
#include "comparator_all.h"

namespace evaluator
{
	struct Stats
	{
		size_t TP, FP, TN, FN;
	};

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

	/**
	  * Class implementing clustering evaluation measures
	  */
	class Evaluator
	{
	public:

		Evaluator();

		void InitEvaluator(const std::string & clutoFile, const std::string & classLabelsFile = "", bool silent = true);

		size_t GetRows() const;

		size_t GetClusteredRows() const;

		size_t GetFoundClusters() const;

		void SetCompareFunction(smartcomparator::compare::CompareFunctionPtr cmp_fun);

		void SetSimilarityMatrix(Matrices::SuperMatrixPtr sim_matrix);

		/*
		  External evaluation methods:
		  */
		double CountPurity();

		double CountNMI();

		double CountRandIndex();

		double CountFmeasure(double beta);

		double CountBCubed(double alpha, double & precision, double & recall);

		/*
		  Internal evaluation methods
		  */
		double CountDunnIndex(smartcomparator::compare::CompareFunctionPtr cmp_fun, bool useImprovedFunctions, double maxValue = 1.0);

		double CountExpectedDensity();

	private:

		void ReadClutoFile(const std::string & clutoFile);

		void ReadClassLabelsFile(const std::string & classLabelsFile);

		Stats CountStats();

		double CountPrecision(Stats & stat);

		double CountRecall(Stats & stat);

		/**
		  * Count minimal distance between two clusters, i.e. minimal distance between two elements in different clusters. We use distance instead of similarity measure (1-sim)
		  */
		double DistanceBetweenClusters(const std::vector<size_t> & vec1, const std::vector<size_t> & vec2, double maxValue = 1.0);

		/**
		  * Cluster distance counting method proposed by: "A geometric approach to cluster validity for normal mixtures" (Bezdek 1997). We use distance instead of similarity measure (1-sim)
		  */
		double DistanceBetweenClusters2(const std::vector<size_t> & vec1, const std::vector<size_t> & vec2);

		/**
		  * Count maxmimal cluster diameter, i.e. maximal distance between two elements in the same cluster. We use distance instead of similarity measure (1-sim)
		  */
		double ClusterDiameter(const std::vector<size_t> & vec);

		/**
		  * Cluster diameter counting method proposed by: "A geometric approach to cluster validity for normal mixtures" (Bezdek 1997). We use distance instead of similarity measure (1-sim)
		  */
		double ClusterDiameter2(const std::vector<size_t> & vec);

		/**
		  * Count similarity between two rows - i and j. Try to use given similarity matrix or use compare function if the matrix is not available
		  */
		double CountSimilarity(size_t i, size_t j);

		/**
		  * Map representing cluster and its members
		  */
		std::map<int, std::vector<size_t> > _clusters;

		/**
		  * Vector containing cluster ID for each element
		  */
		std::vector<int> _clusterIDs;

		/**
		  * Map representing classes and its members
		  */
		std::map<std::string, std::vector<size_t> > _classes;

		/**
		  * Map representing classes and its members >>including outliers<<
		  */
		std::map<std::string, std::vector<size_t> > _classesWOutliers;

		/**
		  * Vector containing class labels for each element
		  */
		std::vector<std::string> _classLabels;

		/**
		  * Sum of all cluster members (matrix rows)
		  */
		size_t _rows;

		/**
		  * Sum of clustered rows (_rows excluding outliers)
		  */
		size_t _clusteredRows;

		/**
		  * Disable stdout printing
		  */
		bool silent;

		/**
		  * Similarity martix
		  */
		Matrices::SuperMatrixPtr _sim_matrix;

		/**
		  * Similarity map used when _sim_matrix is not provided;
		  */
		SimilarityMap _sim_map;

		/**
		  * CompareFunction used to put similarities into _sim_map
		  */
		smartcomparator::compare::CompareFunctionPtr _cmp_fun;
	};
}

#endif //EVALUATOR_H
