/*
    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 <boost/test/unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp>

#include <test_utils/utils.h>

BOOST_AUTO_TEST_CASE(GenericTransformerTest)
{
	Matrices::SuperMatrixPtr m = getTestMatrix();
	smartcomparator::selectors::SelectorPtr sptr(new smartcomparator::selectors::FrequencySelector(m));
	smartcomparator::weights::WeightFeaturePtr wptr(new smartcomparator::weights::MLEWeightFeature(m));
	smartcomparator::transformations::GenericTransformer trans(m, wptr);
	trans.TransformMatrix();
	Matrices::CompressedVectorPtr v1= m->GetCRS()->GetCompressedRow(0);
	std::map<size_t, double> mp_1 = *(v1->GetValues());

	Matrices::SuperMatrixPtr testMatrix = getTestMatrix();
	smartcomparator::compare::CompareFunctionPtr comp = smartcomparator::compare::FunctionFactory::CreateFunction
							("cmp(simfunction=cosine(), weight=MLE())", testMatrix);
	comp->WeightMatrixCopy();
	testMatrix=comp->GetMatrix();
	Matrices::CompressedVectorPtr v2= testMatrix->GetCRS()->GetCompressedRow(0);
	std::map<size_t, double> mp_2 = *(v2->GetValues());

	BOOST_REQUIRE_EQUAL(mp_1.size(), mp_2.size());

	for(size_t i=0; i<mp_1.size()-1; ++i)
		BOOST_REQUIRE_EQUAL(mp_1[i], mp_2[i]);

}


BOOST_AUTO_TEST_CASE(WeightAndWeightCopyMatrixComprasion)
{

	smartcomparator::compare::FunctionFactory ff;
	Matrices::SuperMatrixPtr m_pOriginal = getTestMatrix();

	// Normal weight
	Matrices::SuperMatrixPtr m_pWeight = getTestMatrix();
	smartcomparator::compare::CompareFunctionPtr pCmp = ff.CreateFunction("pmi()", m_pWeight);
	pCmp->WeightMatrix();

	// Copy Weight
	Matrices::SuperMatrixPtr m_pCopySource = getTestMatrix();
	pCmp = ff.CreateFunction("pmi()", m_pCopySource);
	pCmp->WeightMatrixCopy();

	Matrices::SuperMatrixPtr m_pCopyWeight = pCmp->GetMatrix();

	for(size_t j=0; j<m_pOriginal->NumberOfRows(); j++)
	{
		Matrices::CompressedVectorPtr vec= m_pOriginal->GetCRS()->GetCompressedRow(j);
		std::map<size_t, double> mp_1 = *(vec->GetValues());

		vec = m_pWeight->GetCRS()->GetCompressedRow(j);
		std::map<size_t, double> mp_2 = *(vec->GetValues());

		vec = m_pCopySource->GetCRS()->GetCompressedRow(j);
		std::map<size_t, double> mp_3 = *(vec->GetValues());

		vec = m_pCopyWeight->GetCRS()->GetCompressedRow(j);
		std::map<size_t, double> mp_4 = *(vec->GetValues());

		BOOST_REQUIRE_EQUAL(mp_1.size(), mp_3.size());
		BOOST_REQUIRE_EQUAL(mp_2.size(), mp_4.size());

		for(size_t i=0; i<mp_1.size()-1; ++i)
			BOOST_REQUIRE_EQUAL(mp_1[i], mp_3[i]);

		for(size_t i=0; i<mp_2.size()-1; ++i)
			BOOST_REQUIRE_EQUAL(mp_2[i], mp_4[i]);
	}
}

BOOST_AUTO_TEST_CASE(WeightAndCopySimilarityComprasion)
{
	smartcomparator::compare::FunctionFactory ff;
	Matrices::SuperMatrixPtr m_pOriginal = getTestMatrix();
	smartcomparator::compare::CompareFunctionPtr pCmpWithoutWeight = ff.CreateFunction("pmi()", m_pOriginal);


	Matrices::SuperMatrixPtr m_pWeight = getTestMatrix();
	smartcomparator::compare::CompareFunctionPtr pCmpNormal = ff.CreateFunction("pmi()", m_pWeight);
	pCmpNormal->WeightMatrix();

	Matrices::SuperMatrixPtr m_pCopySource = getTestMatrix();
	smartcomparator::compare::CompareFunctionPtr pCmpCopy = ff.CreateFunction("pmi()", m_pCopySource);
	pCmpCopy->WeightMatrixCopy();

	Matrices::SuperMatrixPtr m_pDouble = getTestMatrix();
	smartcomparator::compare::CompareFunctionPtr pCmpDoubleWeight = ff.CreateFunction("pmi()", m_pDouble);
	pCmpDoubleWeight->WeightMatrix();
	pCmpDoubleWeight->WeightMatrixCopy();

	for(size_t i=0; i<m_pOriginal->NumberOfRows();i++)
	{
		for(size_t j=0; j<m_pOriginal->NumberOfRows();j++)
		{
			if(i==j)
				continue;
			double sim1 = pCmpWithoutWeight->Compare(i,j);
			double sim2 = pCmpNormal->Compare(i,j);
			double sim3 = pCmpCopy->Compare(i,j);
			double sim4 = pCmpDoubleWeight->Compare(i,j);
			BOOST_REQUIRE_EQUAL(sim1, sim2);
			BOOST_REQUIRE_EQUAL(sim2, sim3);
			BOOST_REQUIRE_EQUAL(sim3, sim4);
		}
	}
}

BOOST_AUTO_TEST_CASE(GenericTransformerSelectorTest)
{
	Matrices::SuperMatrixPtr m = getTestMatrix();
	Matrices::CompressedVectorPtr v1;
	smartcomparator::weights::WeightFeaturePtr emptyW;
	smartcomparator::filters::FilterFeaturePtr emptyF;
	smartcomparator::selectors::SelectorPtr sptr(new smartcomparator::selectors::FrequencySelector(m, 3,1,1));

	smartcomparator::transformations::GenericTransformer trans(m, emptyW, emptyF,sptr);
	trans.TransformMatrix();

	v1= m->GetRow(0);
	std::map<size_t, double> mp1 = *(v1->GetValues());

	BOOST_REQUIRE_EQUAL((*(v1->GetValues())).size(), 0);
	v1= m->GetRow(1);
	BOOST_REQUIRE_EQUAL((*(v1->GetValues())).size(), 0);
	v1= m->GetRow(2);
	BOOST_REQUIRE_EQUAL((*(v1->GetValues())).size(), 0);
	v1= m->GetRow(3);
	BOOST_REQUIRE_EQUAL((*(v1->GetValues())).size(), 3);
	v1= m->GetRow(4);
	BOOST_REQUIRE_EQUAL((*(v1->GetValues())).size(), 3);

}



BOOST_AUTO_TEST_CASE(GenericTransformerFilterTest)
{
	Matrices::SuperMatrixPtr m = getTestMatrix();

	Matrices::CompressedVectorPtr v1;
	Matrices::FeatureVectorPtr col_feat=m->GetColumnFeatures();
	smartcomparator::weights::WeightFeaturePtr emptyW;
	smartcomparator::filters::FilterFeaturePtr filtr(new smartcomparator::filters::FilterFeature01(col_feat,4));
	smartcomparator::selectors::SelectorPtr emptyS;

	smartcomparator::transformations::GenericTransformer trans(m, emptyW, filtr,emptyS);
	trans.TransformMatrix();

	v1= m->GetRow(0);
	std::map<size_t, double> mp1 = *(v1->GetValues());

	BOOST_REQUIRE_EQUAL((*(v1->GetValues())).size(), 0);
	v1= m->GetRow(1);
	BOOST_REQUIRE_EQUAL((*(v1->GetValues())).size(), 1);
	v1= m->GetRow(2);
	BOOST_REQUIRE_EQUAL((*(v1->GetValues())).size(), 1);
	v1= m->GetRow(3);
	BOOST_REQUIRE_EQUAL((*(v1->GetValues())).size(), 2);
	v1= m->GetRow(4);
	BOOST_REQUIRE_EQUAL((*(v1->GetValues())).size(), 2);
	v1= m->GetRow(5);
	BOOST_REQUIRE_EQUAL((*(v1->GetValues())).size(), 1);
	v1= m->GetRow(6);
	BOOST_REQUIRE_EQUAL((*(v1->GetValues())).size(), 1);
	v1= m->GetRow(7);
	BOOST_REQUIRE_EQUAL((*(v1->GetValues())).size(), 1);
	v1= m->GetRow(8);
	BOOST_REQUIRE_EQUAL((*(v1->GetValues())).size(), 1);
	v1= m->GetRow(9);
	BOOST_REQUIRE_EQUAL((*(v1->GetValues())).size(), 0);
	v1= m->GetRow(10);
	BOOST_REQUIRE_EQUAL((*(v1->GetValues())).size(), 0);
	v1= m->GetRow(11);
	BOOST_REQUIRE_EQUAL((*(v1->GetValues())).size(), 0);
}


