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

static log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("SuperMatrix.comparator.weights.ContingencyTableWeight"));

namespace smartcomparator
{
	namespace weights
	{
		ContingencyTableWeight::ContingencyTableWeight(Matrices::SuperMatrixPtr pMatrix)
			: m_pMatrix(pMatrix)
		{
			CountRowSums();
		}

		void ContingencyTableWeight::CountRowSums()
		{
			if(m_vRowSums.size())
				return;

			m_stFilteredMatrixSum = 0;
			size_t rows = m_pMatrix->NumberOfRows();
			for(size_t row_no = 0; row_no < rows; row_no++)
			{
				double filtered_row_sum = 0;
				Matrices::CompressedVectorPtr v = m_pMatrix->GetRow(row_no);
				std::map<size_t, double> *vals = v->GetValues();
				for(std::map<size_t, double>::iterator col_iter = vals->begin();
						col_iter != vals->end(); ++col_iter)
					filtered_row_sum += col_iter->second;

				m_vRowSums.push_back(filtered_row_sum);
				m_stFilteredMatrixSum += filtered_row_sum;
			}
			LOG4CXX_INFO(logger,"Filtered matrix sum: "<<m_stFilteredMatrixSum);

		}
		void ContingencyTableWeight::CountContingencyTableLocal(Matrices::CompressedVector *row, size_t row_index, size_t column_index)
		{
			// couting according to Evert's PHD Disideration, pages 76,83
			Matrices::FeatureVectorPtr col_features = m_pMatrix->GetColumnFeatures();
			Matrices::FeatureVectorPtr row_features = m_pMatrix->GetRowFeatures();
			
			double O_11 = (*row)[column_index];
			double column_tf = (*col_features)[column_index].GetTermFrequency();

			// first index is equal to corpus number 0 or 1
			// second index is equal to 'this' word if 0 and to other words if 1

			// local prob. definition:
			// 'this' word occurrences in corpus1 (row)
			observed[0][0] = O_11;
			// other words occurrences in corpus1 (row)
			observed[0][1] = m_vRowSums[row_index] - O_11;

			// 'this' word occurrences in corpus2 (mtx - row)
			observed[1][0] = column_tf - O_11; // O_21
			// other words occurrences in corpus2 (mtx - row)
			// + O_11 is because by suming row and coumn tf we have substracted current value (O_11) twice
			observed[1][1] = m_stFilteredMatrixSum - m_vRowSums[row_index] - column_tf + O_11 ;

			// sum of 'this' word occurrences in both corpuses (row and mtx - row)
			C1 = observed[0][0] + observed[1][0];
			// sum of other words occurrences in both corpuses (row and mtx - row)
			C2 = observed[0][1] + observed[1][1];

			// sum of all words in corpus1 (row)
			R1 = observed[0][0] + observed[0][1];
			// sum of all words in corpus2 (mtx - row)
			R2 = observed[1][0] + observed[1][1];

			// sum of all words in both corpuses
			N = R1+R2;

			// will never be equal to 0 (matrix would have to be empty?)
			if (N == 0)
			{
				LOG4CXX_INFO(logger,"OJEZUSMARIA!");
			}
//1.84037e+08
			expected[0][0] = (R1*C1) / N;
			expected[0][1] = (R1*C2) / N;
			expected[1][0] = (R2*C1) / N;
			expected[1][1] = (R2*C2) / N;
		}

		void ContingencyTableWeight::CountContingencyTableGlobal(Matrices::CompressedVector *row, size_t row_index, size_t column_index)
		{
			// couting according to Evert's PHD Disideration, pages 76,83
			Matrices::FeatureVectorPtr col_features = m_pMatrix->GetColumnFeatures();
			Matrices::FeatureVectorPtr row_features = m_pMatrix->GetRowFeatures();
			
			double O_11 = (*row)[column_index];
			double column_tf = (*col_features)[column_index].GetTermFrequency();

			// local prob. definition:
			observed[0][0] = O_11 ; // O_11
			observed[0][1] = m_vRowSums[row_index] - O_11; // O_12
			observed[1][0] = column_tf - O_11; // O_21
			// + O_11 is because by suming row and coumn tf we have substracted current value (O_11) twice
			observed[1][1] = m_stFilteredMatrixSum - m_vRowSums[row_index] - column_tf + O_11 ; // O_22


			C1 = observed[0][0] + observed[1][0];
			C2 = observed[0][1] + observed[1][1];

			R1 = observed[0][0] + observed[0][1];
			R2 = observed[1][0] + observed[1][1];

			N = C1+C2;

			double F = (*col_features)[column_index].GetGlobalTermFrequency();
			double TF = (*row_features)[row_index].GetGlobalTermFrequency();
			double W = m_pMatrix->GetTokenCount();
			expected[0][0] = (TF*F) / W;
			expected[0][1] = (TF*(W-F)) / W;
			expected[1][0] = (F*(W-TF)) / W;
			expected[1][1] = (W*W - TF*W - F*W + TF*F) / W;
		}
	} // namespace weights

}// namespace smartcomparator

