/*
    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 "Beta.h"

namespace smartcomparator {
	namespace weights {


Beta::Beta(
	Matrices::SuperMatrixPtr& 	pMatrix,
	Params const&				pParams,
	ModifierPtrS const&			pModifier)
:
	WeightFeature(pMatrix),
	mModifier(pModifier),
	mParams(pParams)
{
	build();
}

void Beta::Weight(
	size_t 						pRowIndex,
	Matrices::CompressedVector*	pRow,
	std::set<size_t>&			pFilteredIndices)
{
	double fx = (*m_pMatrix->GetRowFeatures())[pRowIndex].GetTermFrequency();
	for(std::set<size_t>::iterator i = pFilteredIndices.begin(); i != pFilteredIndices.end(); ++i){
		double fy 			= (*m_pMatrix->GetColumnFeatures())[*i].GetTermFrequency();
		double fxy			= (*pRow)[*i];
		double betaValue 	= countValue(fx, fy, fxy);
		betaValue			= (*mModifier)(betaValue);
		pRow->SetElement(*i, betaValue);
	}
}

void Beta::setParams(Beta::Params const& pParams){
	mParams = pParams;
}

void Beta::build(){
	size_t N = 0UL;
	for(size_t r=0; r<m_pMatrix->NumberOfRows(); ++r)
		N += (*m_pMatrix->GetRowFeatures())[r].GetTermFrequency();
	mN = static_cast<double>(N);
}

double Beta::countValue(double pFx, double pFy, double pFxy){
	return
		std::pow(pFxy 				/ mN, mParams.q) 					*
		std::pow(pFx 				/ mN, mParams.r) 					*
		std::pow(pFy 				/ mN, mParams.s) 					*
		std::pow((pFx + pFy - pFxy) / mN, -std::max(mParams.t, 0.0)) 	*
		std::pow((pFx + pFy) 		/ mN,  std::min(mParams.t, 0.0))	;
}


/* Modifier functions */
double Beta::Modifier::operator()(double pBetaValue) const {
	return pBetaValue;
}

double Beta::ModifierLn::operator()(double pBetaValue) const {
	return std::log(pBetaValue);
}

double Beta::ModifierInverse::operator()(double pBetaValue) const {
	return 1.0 / pBetaValue;
}

Beta::ModifierMultiplier::ModifierMultiplier(double pMultiplier)
:
	mMultiplier(pMultiplier)
{

}

double Beta::ModifierMultiplier::operator()(double pBetaValue) const {
	return mMultiplier * pBetaValue;
}

	}
}
