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

namespace smartcomparator
{

	namespace compare
	{
		RankEnsembleCompareFunction::RankEnsembleCompareFunction(std::vector<CompareFunctionPtr> pCompare,
									 std::vector<double> vWeights):
		EnsembleCompareFunction(pCompare,vWeights)
		{
		}

		RankEnsembleCompareFunction::~RankEnsembleCompareFunction()
		{
		}

		bool rankCompare(std::pair<size_t, double> n1, std::pair<size_t, double> n2)
		{
			return (n1.second > n2.second);
		}

		double RankEnsembleCompareFunction::Compare(size_t n1, size_t n2)
		{
			double sum = 0;
			size_t n = comparators.size();
			std::vector <std::vector<std::pair<size_t,double> > > n1_ranks;
			for (size_t i=0; i<n; i++)
			{
				std::vector<std::pair<size_t,double> >vec;
				n1_ranks.push_back(vec);

				Matrices::SuperMatrixPtr pMatrix = comparators[i]->GetMatrix();
				Matrices::CompressedVectorPtr row = pMatrix->GetRow(n1);
				size_t k = row->GetUncompresseSize();
				for (size_t j=0; j<k; j++)
				{
					n1_ranks[i].push_back(std::pair<size_t,double>(j,(*row)[j]));
				}
				std::sort(n1_ranks[i].begin(), n1_ranks[i].end(), rankCompare);
			}
			for (size_t i = 0; i<n; i++)
			{
				size_t m = n1_ranks[i].size();
				for (size_t j = 0; j<m; j++)
				{
					if (n1_ranks[i][j].first == n2)
					{
						sum += (m - (j + 1)) * weights[i];
						break;
					}
				}
			}
			sum /= weightsum;
			return sum;
		}

		double RankEnsembleCompareFunction::MinValue() const
		{
			double sum = 0;
			int n = comparators.size();
			for (int i=0; i<n; i++)
			{
				sum += weights[i] * comparators[i]->MinValue();
			}
			sum /= weightsum;
			return sum;
		}

		bool RankEnsembleCompareFunction::IsSymmetrical() const
		{
			bool sym = true;
			for (size_t i=0; i<comparators.size() && sym; i++)
			{
				sym = sym && comparators[i]->IsSymmetrical();
			}
			return sym;
		}

	}
}
