/*
    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.
*/

#include "../comparator_stdheaders.h"
#include "SHD.h"

namespace smartcomparator
{
	namespace simfunctions
	{
		SHD::SHD(Matrices::SuperMatrixPtr pMatrix, double alpha)
			: SimilarityFunction(pMatrix),
			m_dAlpha(alpha)
		{
		}

		SHD::~SHD()
		{
		}

		bool SHD::IsSymmetrical() const
		{
			return false;
		}

		double SHD::CountSimilarity(Matrices::CompressedVector& v1, Matrices::CompressedVector& v2,
				size_t v1ind, size_t v2ind,	const std::set<size_t> &v1Ind, const std::set<size_t> &v2Ind)
		{
			double sim = 0.0, prec_a_b = 0.0, prec_b_a = 0.0, sum_c_a = 0.0, sum_c_b = 0.0;

			double temp_sum = 0.0;
			// Prec(a,b) = \frac{ \sum{c \in a} { | c(a) - c(b) } } { \sum{c \in a} { c(a) } }
			for(std::set<size_t>::const_iterator iter = v1Ind.begin(); iter != v1Ind.end();iter++)
			{
				double c_a = v1[*iter];
				double c_b = v2[*iter];
				sum_c_a += c_a;
				temp_sum += fabs( c_a - c_b );
			}
			if(sum_c_a == 0.0)
				return 0.0;
			prec_a_b = temp_sum / sum_c_a;

			temp_sum = 0;
			// Prec(b,a) = \frac{ \sum{c \in b} { | c(b) - c(a) } } { \sum{c \in b} { c(b) } }
			for(std::set<size_t>::const_iterator iter = v2Ind.begin(); iter != v2Ind.end();iter++)
			{
				double c_a = v1[*iter];
				double c_b = v2[*iter];
				sum_c_b += c_b;
				temp_sum += fabs( c_b - c_a );
			}
			if(sum_c_b == 0.0)
				return 0.0;

			prec_b_a = temp_sum / sum_c_b;

			double f_alfa = 1.0 / ( ( m_dAlpha * 1.0 / prec_a_b ) + (1.0 - m_dAlpha)* (1.0 / prec_b_a ) );

			sim = 1.0 - f_alfa;
			//sim = exp(-f_alfa);
			//sim = 0.0001 / atan(f_alfa - 0.5);
			//sim = pow( 10.0, -1.5* (f_alfa-0.5) );

			return sim;
		}

		double SHD::MinValue() const
		{
			return -100000.0;
		}

	}//namespace simfunctions
}//namespace smartcomparator

