
#include "PartialMSR2B.h"


namespace smartcomparator
{
	namespace simfunctions
	{


PartialMSR2B::PartialMSR2B(
	Matrices::SuperMatrixPtr&	pWeightsMatrix,
	SimilarityFunctionPtr&		pSimilarityFunction,
	SynsetClassSetPtrS&			pSynsetClasses,
	Params&						pParams,
	ParamsB&					pParamsB  )
:
	PartialMSR2Base( pWeightsMatrix, pSimilarityFunction, pSynsetClasses, pParams ),
	mParamsB( pParamsB )
{

}

PartialMSR2B::~PartialMSR2B(){

}


double PartialMSR2B::CountSimilarity(
	Matrices::CompressedVector& pMatrixRow1,
	Matrices::CompressedVector& pMatrixRow2,
	size_t 						pLemmaIndex1,
	size_t 						pLemmaIndex2,
	const std::set<size_t>&		pNonZeroFeaturesIndices1,
	const std::set<size_t>&		pNonZeroFeaturesIndices2 )
{
	return InnerCountSimilarityB( pMatrixRow1, pMatrixRow2, pLemmaIndex1,
		pLemmaIndex2, pNonZeroFeaturesIndices1, pNonZeroFeaturesIndices2 );
}


void PartialMSR2B::init( Matrices::SuperMatrixPtr& pFrequencies ){
	PartialMSR2Base::init( pFrequencies );

	size_t last = boost::lexical_cast<size_t>( mSmCxF->GetRowFeatures()->rbegin()->GetLabel() );
	mClsCounter.resize( last + 1UL, 0UL );
}


/*
Wariant B - inne wersja A
Funkcja fcz =
1. Jeżeli są przynajmniej k=2 lokalnie istotne cechy wspólne dla lematów x i y, takie że cechy te opisują tę samą klasę (poza tym mogą też inne) to zwracamy true.
2. Jeżeli lematy mają więcej niż n=2 lokalnie istotne cechy wspólne, ale opisujące różne klasy, to zwracamy true.
Parametry k i n również mogą być optymalizowane.
*/
double PartialMSR2B::InnerCountSimilarityB(
	Matrices::CompressedVector& pMatrixRow1,
	Matrices::CompressedVector& pMatrixRow2,
	size_t 						pLemmaIndex1,
	size_t 						pLemmaIndex2,
	const std::set<size_t>&		pNonZeroFeaturesIndices1,
	const std::set<size_t>&		pNonZeroFeaturesIndices2 )
{
	//DONE: 1) features mapping required: WeightedWords -> WeightedClasses

	typedef unsigned int UINT;
	UINT diffCls = 0U;

	bool pCompute = false;
	memset( &mClsCounter[0], 0, mClsCounter.size() * sizeof(size_t) );

	std::map<size_t, double>* row1Values 		= pMatrixRow1.GetValues();
	std::map<size_t, double>* row2Values 		= pMatrixRow2.GetValues();
	std::map<size_t, double>::iterator row1Iter = row1Values->begin();
	std::map<size_t, double>::iterator row1End 	= row1Values->end();
	for(; ( row1Iter != row1End ) && !pCompute; ++row1Iter ){

		size_t clsFeatureIdx = (*mWWordsToWClass)[ row1Iter->first ];
		if( clsFeatureIdx == static_cast<size_t>(-1) )
			continue;

		// DONE: 1)
		// check if feature entrophy is small enough
		if( mSmCxF->GetColumnFeatures()->at( clsFeatureIdx ).GetEntropy() > mMaxEntrophy )
			continue;

		// check if both lemmas have not the same feature
		if( row2Values->find( row1Iter->first ) == row2Values->end() )
			continue;

		// check if feature weights for this lemmas is less than min
		if( pMatrixRow1[ row1Iter->first ] <= mParams.minFeatureWeightForLemma ||
			pMatrixRow2[ row1Iter->first ] <= mParams.minFeatureWeightForLemma )
			continue;

		// well... it seems that features are ok but...
		// is it enough?
		if( ++diffCls > mParamsB.n )
			pCompute = true;

		// Are there at least k features that describe both lemmas and these features belong to the same class?
		size_t rowsNum = mSmCxF->GetCRS()->NumberOfRows();
		for( size_t c=0UL; c<rowsNum; ++c ){
			// DONE: 1)
			double cell = mSmCxF->GetCell( c, clsFeatureIdx );
			if( cell <= 0.0 )
				continue;
			if( ++mClsCounter[ c ] >= mParamsB.k ){
				pCompute = true;
				break;
			}
		}
	}

	return pCompute ?
		mSimFunction->CountSimilarity(
			pMatrixRow1, pMatrixRow2,
			pLemmaIndex1, pLemmaIndex2,
			pNonZeroFeaturesIndices1, pNonZeroFeaturesIndices2 ) :
		MinValue();
}


	}
}


