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

namespace smartcomparator
{
	namespace weights
	{
		LogEntNormalizeWeight::LogEntNormalizeWeight(Matrices::SuperMatrixPtr m,  bool useFilteredEntropy) 
			: WeightFeature(m),
			m_UseFilteredEntropy(useFilteredEntropy)
		{
		}

		LogEntNormalizeWeight::~LogEntNormalizeWeight(void)
		{
		}


		void LogEntNormalizeWeight::Weight(size_t rowindex, Matrices::CompressedVector *v, std::set<size_t> &filteredIndices) 
		{
			if(v->GetValues()->size() == 0 )
				return;
			//double sum = SumAndLog(v, filteredIndices);

			Matrices::FeatureVectorPtr row_features = m_pMatrix->GetRowFeatures();
			double entropy = (*row_features)[rowindex].GetEntropy();

			DevideByEntropy(v, filteredIndices, entropy);
			Measures::NormalizeVector(*v);

		}

		double LogEntNormalizeWeight::SumAndLog(Matrices::CompressedVector *v, std::set<size_t> &filteredIndices)
		{
			double sum = 0;

			if(m_UseFilteredEntropy)
			{

				for(std::set<size_t>::const_iterator iter = filteredIndices.begin(); iter != filteredIndices.end();iter++)
				{
					double val = (*v)[(*iter)] + 1;
					if(val == 1 )
						continue;
					val = log(val);
					sum += val;
					v->SetElement(*iter, val);			
				}

			}
			else
			{
				const std::map<size_t, double> &map = *v->GetValues();
				for(std::map<size_t, double>::const_iterator iter = map.begin(); iter != map.end();iter++)
				{
					double val = (iter->second) + 1;
					if(val == 1 )
						continue;
					val = log(val);
					sum += val;
					v->SetElement(iter->first, val);			
				}
			}
			return sum;
		}


		double LogEntNormalizeWeight::CountEntropy(Matrices::CompressedVector *v, std::set<size_t> &filteredIndices, double sum)
		{
			double entropy = 0;
			if(m_UseFilteredEntropy)
			{
				for(std::set<size_t>::const_iterator iter = filteredIndices.begin(); iter != filteredIndices.end();iter++)
				{
					double val = (*v)[(*iter)];
					double p = val / sum;
					if(p)
						entropy += p * log(p);
				}
			}
			else
			{
				const std::map<size_t, double> &map = *v->GetValues();
				for(std::map<size_t, double>::const_iterator iter = map.begin(); iter != map.end();iter++)
				{
					double val = iter->second;
					double p = val / sum;
					if(p)
						entropy += p * log(p);
				}
			}
			return (entropy != 0)?-entropy:0;
		}

		void LogEntNormalizeWeight::DevideByEntropy(Matrices::CompressedVector *v, std::set<size_t> &filteredIndices, double entropy)
		{
			if(entropy)
			{
				if(m_UseFilteredEntropy)
				{
					for(std::set<size_t>::const_iterator iter = filteredIndices.begin(); iter != filteredIndices.end();iter++)
					{

						double val = (*v)[(*iter)];
						if(val == 0 )
							continue;
						v->SetElement(*iter, val / entropy);
					}
				}//if(m_UseFilteredEntropy)
				else
				{
					const std::map<size_t, double> &map = *v->GetValues();
					for(std::map<size_t, double>::const_iterator iter = map.begin(); iter != map.end();iter++)
					{
						double val = iter->second;
						if(val == 0 )
							continue;
						v->SetElement(iter->first, val / entropy);
					}
				}// else if(m_UseFilteredEntropy)
			}// if(entropy)
		}// DevideByEntropy
	}
}
