/*
    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 "FunctionFactory.h"
#include "FunctionFactory2.h"

static log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("SuperMatrix.comparator.compare.FunctionFactory"));

namespace smartcomparator
{
	namespace compare
	{
		/// idea by Ron Natalie, found on http://bytes.com/forum/thread62700.html
		template <typename T> T real_min()
		{
			if(std::numeric_limits<T>::is_integer) return std::numeric_limits<T>::min();
			else return -std::numeric_limits<T>::max();
		}

		void GetStrLower(STR2STR &name2val, const std::string& name, std::string &result, size_t &args_count)
		{
			if( name2val.find(name) != name2val.end() )
			{
				result = name2val[name];
				boost::to_lower(result);
				args_count++;
			}
		}
		void GetString(STR2STR &name2val, const std::string& name, std::string &result, size_t &args_count)
		{
			if( name2val.find(name) != name2val.end() )
			{
				result = name2val[name];
				args_count++;
			}
		}
		void GetBool(STR2STR &name2val, const std::string& name, bool &result, size_t &args_count)
		{
			if( name2val.find(name) != name2val.end() )
			{
				std::string val = name2val[name];
				boost::to_lower(val);

				if( val == "false" )
					result = false;
				else if( val == "true")
					result = true;
				else
					throw std::runtime_error("Unknow value for '"+name+"': " + name2val[name]);
				args_count++;
			}
		}

		/**
		 * \param lower_bound tested with operator < (so returned number has to be grater then lower_bound)
		 * \param upper_bound tested with operator >=(so returned number has to be lower or equal to upper_bound)
		 */
		template<class T> void GetNumber(STR2STR &name2val, const std::string& name, T &result , size_t &args_count,
		T lower_bound = real_min<T>(), T upper_bound = std::numeric_limits<T>::max() )

		{
			if( name2val.find(name) != name2val.end() )
			{
				result = boost::lexical_cast<T> ( name2val[name] );
				if(result < lower_bound || result >= upper_bound)
					throw std::runtime_error("has to be in range ");
				args_count++;
			}
		}

		CompareFunctionPtr FunctionFactory::CreateFunction(const std::string & str, Matrices::SuperMatrixPtr pMatrix)
		{
			boost::regex function_pattern("\\s*(\\S+)\\s*\\(\\s*([^\\)]*)\\s*\\)\\s*");
			std::string function_str = str;
			boost::trim(function_str);

			boost::smatch match;

			if (boost::regex_match(function_str, match, function_pattern) )
			{
				std::string f_name = match[1];
				std::string f_args = match[2];
				boost::trim(f_name);
				boost::trim(f_args);

				STR2STR name2val;
				PrepareArgs(f_args, name2val);

				if (f_name == "cmp")
				{
					FunctionFactory2 ff2;
					return ff2.CreateComparator(str, pMatrix);
				}
				if (f_name == "domain_comparator")
					return CreateDomainComparator(name2val, pMatrix);
				if (f_name == "file_sim")
					return CreateFileSimFunction(name2val, pMatrix);
				if (f_name == "tfidf")
					return CreateTfIdf(pMatrix);
				if (f_name == "rff")
					return CreateRFF(name2val, pMatrix);
				if (f_name == "rwf_loglikelihood")
					return CreateRWFLogLikelihood(name2val, pMatrix);
				if (f_name == "rwf_evertsmi")
					return CreateRWFEvertsMI(name2val, pMatrix);
				if (f_name == "rwf_chi2")
					return CreateRWFChi2(name2val, pMatrix);
				if (f_name == "rwf_pmi")
					return CreateRWFPMI(name2val, pMatrix);
				if (f_name == "rwf_lin")
					return CreateRWFLin(name2val, pMatrix);
				if (f_name == "rwf_lin_mcf")
					return CreateMCFRWFLin(name2val, pMatrix);
				if (f_name == "rwf_lin_filtered")
					return CreateRWFLinFiltered(name2val, pMatrix);
				if (f_name == "rwf_zscore")
					return CreateRWFZScore(name2val, pMatrix);
				if (f_name == "pmi")
					return CreatePMI(name2val, pMatrix);
				if (f_name == "lin")
					return CreateMILin(name2val,f_args, pMatrix);
				if (f_name == "lin_cos")
					return CreateMILinCosine(name2val,f_args, pMatrix);
				if (f_name == "crm_dmi")
					return CreateCRMDMI(f_args, pMatrix);
				if (f_name == "simple_plain_lin")
					return CreatePlainSimpleLin(f_args, pMatrix);
				if (f_name == "cos")
					return CreateCosine(f_args, pMatrix);
				if (f_name == "logent")
					return CreateLogEnt(f_args, pMatrix);
				if (f_name == "shd")
					return CreateSHD(f_args, pMatrix);
				if (f_name == "dice")
					return CreateDice(f_args, pMatrix);
				if (f_name == "jaccard")
					return CreateJaccard(f_args, pMatrix);
				if (f_name == "mi_quant_cos")
					return CreateQuantifiedCos(name2val, pMatrix);
				if (f_name == "pmi_quant")
					return CreatePMIQuantified(name2val, pMatrix);
				if (f_name == "mi_quant_lin")
					return CreateQuantifiedLin(name2val, pMatrix);
				if (f_name == "rwf_cos")
					return CreateRWFNoWeight(name2val, pMatrix);
				if (f_name == "rwf_lin_ensemble")
					return CreateRWFLinEnsemble(name2val, pMatrix);
				if (f_name == "rwf_lin_scaled")
					return CreateRWFLinScaled(name2val, pMatrix);
				if (f_name == "test")
				{
					//std::vector<size_t> o;
					//o.push_back(pMatrix->NumberOfColumns() - 1);
					//return CompareFunctionPtr(new MILinsComparision( pMatrix)) ;
				}
			}

			FunctionFactory2 ff2;
			return ff2.CreateComparator(str, pMatrix);

			//throw std::runtime_error("Mallformed function: " + str );
			//return CompareFunctionPtr();
		}//CreateFunction
		CompareFunctionPtr FunctionFactory::CreateDomainComparator(STR2STR &name2val, Matrices::SuperMatrixPtr pMatrix)
		{
			std::string compareF, domainFilename, labelFile;
			size_t args_count = 0;
			if(name2val.find("compare_function")!=name2val.end())
			{
				compareF= name2val["compare_function"];
				args_count++;
			}
			if(name2val.find("domain_file")!=name2val.end())
			{
				domainFilename = name2val["domain_file"];
				args_count++;
			}
			if(name2val.find("label_file")!=name2val.end())
			{
				labelFile = name2val["label_file"];
				args_count++;
			}

			if ( args_count != name2val.size())
				throw std::runtime_error("Some aguments were unparsed in CreateDomainComparator");
			LOG4CXX_INFO(logger,"Creating domain comparator for function "<<compareF<<" and domains from file "
						 <<domainFilename);
			return CompareFunctionPtr(new DomainComparator(pMatrix,domainFilename, labelFile,compareF));
		}

		CompareFunctionPtr FunctionFactory::CreateFileSimFunction(STR2STR &name2val, Matrices::SuperMatrixPtr pMatrix)
		{
			size_t args_count = 0;
			std::string simMatrix;
			if(name2val.find("sim_matrix")!=name2val.end())
			{
				simMatrix= name2val["sim_matrix"];
				args_count++;
			}

			if ( args_count != name2val.size())
				throw std::runtime_error("Some aguments were unparsed in CreateFileSimFunction");

			LOG4CXX_INFO(logger, "Creating file similarity function based on matrix: "
						 << simMatrix);

			std::string ff2string = "cmp(simfunction=filesim(sim_matrix=" + simMatrix + "))";

			FunctionFactory2 f;
			return f.CreateComparator(ff2string, pMatrix);
			//return CompareFunctionPtr(new FileSimComparision(pMatrix, simMatrix));
		}//CreateRWFLinFiltered

		CompareFunctionPtr FunctionFactory::CreateRWFLinFiltered(STR2STR &name2val, Matrices::SuperMatrixPtr pMatrix)
		{
			size_t args_count = 0;
			std::string colmintf = "5";
			std::string noisePrec = "0.99", threshold = "0";

			std::string row_minnz = "0"; // those are initialized in GetRowFreqFilter
			std::string row_mintf = "0";
			std::string row_minTF = "0";
			GetRowFreqFilter(name2val, row_mintf, row_minTF, row_minnz, args_count);

			GetString(name2val, "colmintf", colmintf,  args_count);
			GetString(name2val, "noise", noisePrec, args_count);
			GetString(name2val, "threshold", threshold, args_count);

			//weights::RankBuilderPtr pRankBuilder = CreateRankBuilder(name2val, pMatrix, args_count);
			std::string rBuilderStr = CreateRankBuilderString(name2val, pMatrix, args_count);

			std::string cNoise = boost::lexical_cast<std::string> ((size_t) (pMatrix->NumberOfColumns() * boost::lexical_cast<double>(noisePrec)));
			std::string filterStr = "noisektf(k=" + cNoise + ",mintf=" + colmintf + ")";

			std::string selectorStr = "frequency(min_nz=" + row_minnz + ",min_tf=" + row_mintf + ",min_TF=" + row_minTF + ")";

			std::string weigherStr = "rwf_lin_filtered(rankbuilder=" + rBuilderStr + ",threshold=" + threshold + ")";

			std::string simStr = "cosine()";

			std::string cmpStr = "cmp(weight=" + weigherStr + ",selector=" + selectorStr + ",simfunction=" + simStr +
					     ",filter=" + filterStr + ")";

			if ( args_count != name2val.size())
				throw std::runtime_error("Some aguments were unparsed in CreateRWFLinFiltered");

			LOG4CXX_INFO(logger, "Creating rwf lin filtered function with params: " << "noise: " << noisePrec << ", col_mintf: "
						 << colmintf << ", treshold: " << threshold);

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

			//return CompareFunctionPtr(new RWFMILinFilteredComparision(pMatrix, pRankBuilder, noisePrec,
			//colmintf, threshold, row_minnz, row_mintf, row_minTF) );
		}//CreateRWFLinFiltered

		CompareFunctionPtr FunctionFactory::CreateMCFRWFLin(STR2STR &name2val, Matrices::SuperMatrixPtr pMatrix)
		{
			size_t args_count = 0;
			std::string mintf = "5";
			std::string noisePrec = "0.99", threshold = "0", ratio = "0.14";

			std::string row_minnz; // those are initialized in GetRowFreqFilter
			std::string row_mintf;
			std::string row_minTF;
			GetRowFreqFilter(name2val, row_mintf, row_minTF, row_minnz, args_count);

			GetString(name2val, "colmintf", mintf,  args_count);
			GetString(name2val, "noise", noisePrec, args_count);
			GetString(name2val, "threshold", threshold, args_count);
			GetString(name2val, "ratio", ratio, args_count);

			std::string rankStr = CreateRankBuilderString(name2val, pMatrix, args_count);

			if ( args_count != name2val.size())
				throw std::runtime_error("Some aguments were unparsed in CreateRWFLin");

			LOG4CXX_INFO(logger, "Creating rwf lin (MCF) function with params: " << "noise: " << noisePrec << ", mintf: "
						 << mintf << ", treshold: " << threshold);

			std::string cNoise = boost::lexical_cast<std::string> ((size_t) (pMatrix->NumberOfColumns() * boost::lexical_cast<double>(noisePrec)));
			std::string filterStr = "noisektf(k=" + cNoise + ",mintf=" + mintf + ")";

			std::string selectorStr = "frequency(min_nz=" + row_minnz + ",min_tf=" + row_mintf + ",min_TF=" + row_minTF + ")";

			std::string weigherStr = "rwf_lin(rankbuilder=" + rankStr + ",threshold=" + threshold +")";
			
			std::string innerSimStr = "cosine()";
			
			std::string simStr = "mcf(threshold=" + ratio + ",weight=" + weigherStr + ",sim_inner=" + innerSimStr + ")";
			
			std::string cmpStr = "cmp(weight=" + weigherStr + ",selector=" + selectorStr + ",simfunction=" + simStr +
					     ",filter=" + filterStr + ")";
			
			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

			//return CompareFunctionPtr(new MCFRWFLinComparision(pMatrix, pRankBuilder, noisePrec, mintf,
			//threshold, ratio, row_minnz, row_mintf, row_minTF) );
		}//CreateMCFRWFLin

		CompareFunctionPtr FunctionFactory::CreateRWFLin(STR2STR &name2val, Matrices::SuperMatrixPtr pMatrix)
		{
			size_t args_count = 0;
			std::string col_mintf = "5";
			std::string noisePrec = "0.99", threshold = "0";

			std::string row_minnz; // those are initialized in GetRowFreqFilter
			std::string row_mintf;
			std::string row_minTF;
			GetRowFreqFilter(name2val, row_mintf, row_minTF, row_minnz, args_count);

			GetString(name2val, "colmintf", col_mintf,  args_count);
			GetString(name2val, "noise", noisePrec, args_count);
			GetString(name2val, "threshold", threshold, args_count);

			std::string rankStr = CreateRankBuilderString(name2val, pMatrix, args_count);

			if ( args_count != name2val.size())
				throw std::runtime_error("Some aguments were unparsed in CreateRWFLin");

			LOG4CXX_INFO(logger, "Creating rwf lin function with params: " << "noise: " << noisePrec << ", col_mintf: "
					<< col_mintf << ", treshold: " << threshold << ", row_mintf: " << row_mintf << ", row_minnz: "
					<< row_minnz << ", row_minTF:" << row_minTF);

			std::string cNoise = boost::lexical_cast<std::string> ((size_t) (pMatrix->NumberOfColumns() * boost::lexical_cast<double>(noisePrec)));
			std::string filterStr = "noisektf(k=" + cNoise + ",mintf=" + col_mintf + ")";

			std::string selectorStr = "frequency(min_nz=" + row_minnz + ",min_tf=" + row_mintf + ",min_TF=" + row_minTF + ")";

			std::string weigherStr = "rwf_lin(rankbuilder=" + rankStr + ",threshold=" + threshold +")";

			std::string simStr = "cosine()";

			std::string cmpStr = "cmp(weight=" + weigherStr + ",selector=" + selectorStr + ",simfunction=" + simStr +
					     ",filter=" + filterStr + ")";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

			//return CompareFunctionPtr(new RWFMILinComparision(pMatrix, pRankBuilder, noisePrec, col_mintf,
			//threshold, row_minnz, row_mintf, row_minTF) );
		}//CreateRWFLin

		CompareFunctionPtr FunctionFactory::CreateRWFEvertsMI(STR2STR &name2val, Matrices::SuperMatrixPtr pMatrix)
		{
			size_t args_count = 0;
			std::string col_mintf = "5";
			std::string noisePrec = "0.99", threshold = "0";

			std::string row_minnz; // those are initialized in GetRowFreqFilter
			std::string row_mintf;
			std::string row_minTF;
			GetRowFreqFilter(name2val, row_mintf, row_minTF, row_minnz, args_count);

			GetString(name2val, "colmintf", col_mintf,  args_count);
			GetString(name2val, "noise", noisePrec, args_count);
			GetString(name2val, "threshold", threshold, args_count);

			std::string rankStr = CreateRankBuilderString(name2val, pMatrix, args_count);

			if ( args_count != name2val.size())
				throw std::runtime_error("Some aguments were unparsed in CreateRWFEversMI");

			LOG4CXX_INFO(logger, "Creating rwf evetrs mi function with params: " << "noise: " << noisePrec << ", col_mintf: "
						 << col_mintf << ", row_mintf: " << row_mintf << ", row_minnz: " << row_minnz << ", row_minTF:" << row_minTF
						 << ", mi threshold: " << threshold);


			std::string cNoise = boost::lexical_cast<std::string> ((size_t) (pMatrix->NumberOfColumns() * boost::lexical_cast<double>(noisePrec)));
			std::string filterStr = "noisektf(k=" + cNoise + ",mintf=" + col_mintf + ")";

			std::string selectorStr = "frequency(min_nz=" + row_minnz + ",min_tf=" + row_mintf + ",min_TF=" + row_minTF + ")";

			std::string weigherStr = "rwf_evertsmi(rankbuilder=" + rankStr + ",mi_threshold=" + threshold +")";

			std::string simStr = "cosine()";

			std::string cmpStr = "cmp(weight=" + weigherStr + ",selector=" + selectorStr + ",simfunction=" + simStr +
					     ",filter=" + filterStr + ")";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

			//return CompareFunctionPtr(new RWFEvertsMIComparision(pMatrix, pRankBuilder, noisePrec, col_mintf, row_minnz, row_mintf, row_minTF, threshold) );
		}//CreateRWFEvertsMI

		CompareFunctionPtr FunctionFactory::CreateRWFChi2(STR2STR &name2val, Matrices::SuperMatrixPtr pMatrix)
		{
			size_t args_count = 0;
			std::string col_mintf = "5";
			std::string noisePrec = "0.99", threshold = "0";

			std::string row_minnz; // those are initialized in GetRowFreqFilter
			std::string row_mintf;
			std::string row_minTF;
			GetRowFreqFilter(name2val, row_mintf, row_minTF, row_minnz, args_count);

			GetString(name2val, "colmintf", col_mintf,  args_count);
			GetString(name2val, "noise", noisePrec, args_count);
			GetString(name2val, "threshold", threshold, args_count);

			std::string rankStr = CreateRankBuilderString(name2val, pMatrix, args_count);

			if ( args_count != name2val.size())
				throw std::runtime_error("Some aguments were unparsed in CreateRWFCHi2");

			LOG4CXX_INFO(logger, "Creating rwf chi2 function with params: " << "noise: " << noisePrec << ", col_mintf: "
						 << col_mintf << ", row_mintf: " << row_mintf << ", row_minnz: " << row_minnz << ", row_minTF:" << row_minTF
						 << ", threshold: " << threshold);

			std::string cNoise = boost::lexical_cast<std::string> ((size_t) (pMatrix->NumberOfColumns() * boost::lexical_cast<double>(noisePrec)));
			std::string filterStr = "noisektf(k=" + cNoise + ",mintf=" + col_mintf + ")";

			std::string selectorStr = "frequency(min_nz=" + row_minnz + ",min_tf=" + row_mintf + ",min_TF=" + row_minTF + ")";

			std::string weigherStr = "rwf_chi2(rankbuilder=" + rankStr + ",threshold=" + threshold +")";

			std::string simStr = "cosine()";

			std::string cmpStr = "cmp(weight=" + weigherStr + ",selector=" + selectorStr + ",simfunction=" + simStr +
					     ",filter=" + filterStr + ")";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

			//return CompareFunctionPtr(new RWFChi2Comparision(pMatrix, pRankBuilder, noisePrec, col_mintf, row_minnz, row_mintf, row_minTF, threshold) );
		}//CreateRWFChi2

		CompareFunctionPtr FunctionFactory::CreateRFF(STR2STR &name2val, Matrices::SuperMatrixPtr pMatrix)
		{
			//RFFComparision::RFFComparision(Matrices::SuperMatrixPtr pMatrix,std::string simMatrixPath,size_t top_k=100,double simTreshold=0.04,size_t TFTreshold=10,double weightTreshold=4);
			size_t args_count = 0;
			std::string simMatrixPath;
			std::string top_k="100";
			std::string TFTreshold="10";
			std::string simTreshold = "0.04";
			std::string weightTreshold = "4";

			if(name2val.find("sim_matrix")!=name2val.end())
			{
				simMatrixPath= name2val["sim_matrix"];
				args_count++;
			}
			GetString(name2val, "top_k", top_k, args_count);
			GetString(name2val, "TF_treshold", TFTreshold, args_count);
			GetString(name2val,"sim_treshold",simTreshold,args_count);
			GetString(name2val,"weight_treshold",weightTreshold,args_count);


			if ( args_count != name2val.size())
				throw std::runtime_error("Some aguments were unparsed in CreateRFF");

			LOG4CXX_INFO(logger,"Creating rff function with params: " << "sim_matrix: " << simMatrixPath << ", top_k: "
						 << top_k << ", TF_treshold: " << TFTreshold << ", sim_treshold: " << simTreshold << ", weight_treshold:" << weightTreshold);

			std::string selectorStr = "RFF(TFThreshold=" + TFTreshold + ",weightThreshold=" + weightTreshold + ")";

			std::string weigherStr = "rff(simmatrix=" + simMatrixPath + ",top_k=" + top_k + ",sim_threshold=" +
						 simTreshold + ",selector=" + selectorStr + ")";

			std::string simStr = "lin()";

			std::string cmpStr = "cmp(weight=" + weigherStr + ",selector=" + selectorStr + ",simfunction=" + simStr +
					     ")";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

			//return CompareFunctionPtr(new RFFComparision(pMatrix,simMatrixPath,top_k,simTreshold,TFTreshold,weightTreshold) );
		}//CreateRFF

		CompareFunctionPtr FunctionFactory::CreateRWFLogLikelihood(STR2STR &name2val, Matrices::SuperMatrixPtr pMatrix)
		{
			size_t args_count = 0;
			std::string col_mintf = "5";
			std::string noisePrec = "0.99", threshold = "0";

			std::string row_minnz; // those are initialized in GetRowFreqFilter
			std::string row_mintf;
			std::string row_minTF;
			GetRowFreqFilter(name2val, row_mintf, row_minTF, row_minnz, args_count);

			GetString(name2val, "colmintf", col_mintf,  args_count);
			GetString(name2val, "noise", noisePrec, args_count);
			GetString(name2val, "threshold", threshold, args_count);

			std::string rankStr = CreateRankBuilderString(name2val, pMatrix, args_count);

			if ( args_count != name2val.size())
				throw std::runtime_error("Some aguments were unparsed in CreateRWFPMI");

			LOG4CXX_INFO(logger, "Creating rwf log likelihood function with params: " << "noise: " << noisePrec << ", col_mintf: "
						 << col_mintf << ", row_mintf: " << row_mintf << ", row_minnz: " << row_minnz << ", row_minTF:" << row_minTF
						 << ", ll threshold: " << threshold);

			std::string cNoise = boost::lexical_cast<std::string> ((size_t) (pMatrix->NumberOfColumns() * boost::lexical_cast<double>(noisePrec)));
			std::string filterStr = "noisektf(k=" + cNoise + ",mintf=" + col_mintf + ")";

			std::string selectorStr = "frequency(min_nz=" + row_minnz + ",min_tf=" + row_mintf + ",min_TF=" + row_minTF + ")";

			std::string weigherStr = "rwf_log(rankbuilder=" + rankStr + ",threshold=" + threshold +")";

			std::string simStr = "cosine()";

			std::string cmpStr = "cmp(weight=" + weigherStr + ",selector=" + selectorStr + ",simfunction=" + simStr +
					     ",filter=" + filterStr + ")";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);


			//return CompareFunctionPtr(new RWFLogLikelihoodComparision(pMatrix, pRankBuilder, noisePrec, col_mintf, row_minnz, row_mintf, row_minTF, threshold) );
		}//CreateRWFLogLikelihood

		CompareFunctionPtr FunctionFactory::CreateRWFPMI(STR2STR &name2val, Matrices::SuperMatrixPtr pMatrix)
		{
			size_t args_count = 0;
			std::string col_mintf = "5";
			std::string noisePrec = "0.99", threshold = "0";
			std::string discount = "false";

			std::string row_minnz; // those are initialized in GetRowFreqFilter
			std::string row_mintf;
			std::string row_minTF;
			GetRowFreqFilter(name2val, row_mintf, row_minTF, row_minnz, args_count);

			GetString(name2val, "colmintf", col_mintf,  args_count);
			GetString(name2val, "noise", noisePrec, args_count);
			GetString(name2val, "threshold", threshold, args_count);
			GetString(name2val, "discount", discount, args_count);

			std::string rankStr = CreateRankBuilderString(name2val, pMatrix, args_count);

			if ( args_count != name2val.size())
				throw std::runtime_error("Some aguments were unparsed in CreateRWFPMI");

			LOG4CXX_INFO(logger, "Creating rwf pmi function with params: " << "discount: " << discount
						 << "noise: " << noisePrec << ", col_mintf: " << col_mintf << ", treshold: "
						 << threshold << ", row_mintf: " << row_mintf << ", row_minnz: " << row_minnz << ", row_minTF:"
						 << row_minTF);

			std::string cNoise = boost::lexical_cast<std::string> ((size_t) (pMatrix->NumberOfColumns() * boost::lexical_cast<double>(noisePrec)));
			std::string filterStr = "noisektf(k=" + cNoise + ",mintf=" + col_mintf + ")";

			std::string selectorStr = "frequency(min_nz=" + row_minnz + ",min_tf=" + row_mintf + ",min_TF=" + row_minTF + ")";

			std::string weigherStr = "rwf_pmi(rankbuilder=" + rankStr + ",threshold=" + threshold +")";

			std::string simStr = "cosine()";

			std::string cmpStr = "cmp(weight=" + weigherStr + ",selector=" + selectorStr + ",simfunction=" + simStr +
					     ",filter=" + filterStr + ")";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

			//return CompareFunctionPtr(new RWFPMIComparision(pMatrix, pRankBuilder, noisePrec, col_mintf, discount,
			//threshold, row_minnz, row_mintf, row_minTF) );
		}//CreateRWFPMI

		CompareFunctionPtr FunctionFactory::CreateRWFZScore(STR2STR &name2val, Matrices::SuperMatrixPtr pMatrix)
		{
			size_t args_count = 0;
			std::string mintf = "5";
			std::string noisePrec = "0.99", rzmin = "2.57";
			std::string type = "global";

			std::string row_minnz; // those are initialized in GetRowFreqFilter
			std::string row_mintf;
			std::string row_minTF;

			GetRowFreqFilter(name2val, row_mintf, row_minTF, row_minnz, args_count);

			GetString(name2val, "colmintf", mintf,  args_count);
			GetString(name2val, "noise", noisePrec, args_count);
			GetString(name2val, "rz", rzmin, args_count);
			GetStrLower(name2val, "type", type, args_count);

			std::string rankStr = CreateRankBuilderString(name2val, pMatrix, args_count);

			std::string cNoise = boost::lexical_cast<std::string> ((size_t) (pMatrix->NumberOfColumns() * boost::lexical_cast<double>(noisePrec)));
			std::string filterStr = "noisektf(k=" + cNoise + ",mintf=" + mintf + ")";

			std::string selectorStr = "frequency(min_nz=" + row_minnz + ",min_tf=" + row_mintf + ",min_TF=" + row_minTF + ")";

			std::string simStr = "cosine()";

			std::string weigherStr = "";

			if ( args_count != name2val.size())
				throw std::runtime_error("Some aguments were unparsed in CreateRWFZScore");

			if(type == "global")
				weigherStr = "rwf_zscore(rankbuilder=" + rankStr + ",threshold=" + rzmin + ")";
			//return CompareFunctionPtr(new RWFZScoreRankComparision(pMatrix, pRankBuilder, noisePrec, mintf, rzmin,
			//						   row_minnz, row_mintf, row_minTF) );
			if(type == "inmatrix")
				weigherStr = "rwf_zscore_in_matrix(rankbuilder=" + rankStr + ",threshold=" + rzmin + ")";
			//return CompareFunctionPtr(new RWFZScoreInMatrixComparision(pMatrix, pRankBuilder, noisePrec, mintf, rzmin,
			//						   row_minnz, row_mintf, row_minTF) );
			if(type == "local")
				weigherStr = "rwf_zscore_local(rankbuilder=" + rankStr + ",threshold=" + rzmin + ")";
			//return CompareFunctionPtr(new RWFLocalZScoreComparision(pMatrix, pRankBuilder, noisePrec, mintf, rzmin,
			//row_minnz, row_mintf, row_minTF) );
			if(weigherStr == "")
				throw std::runtime_error( (std::string("Unknown zscore type:") + type));

			std::string cmpStr = "cmp(weight=" + weigherStr + ",selector=" + selectorStr + ",simfunction=" + simStr +
					     ",filter=" + filterStr + ")";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

		}//CreateRWFZScore

		weights::RankBuilderPtr FunctionFactory::CreateRankBuilder(STR2STR &name2val, Matrices::SuperMatrixPtr pMatrix, size_t &args_count)
		{
			size_t rank_size = 350;
			bool uniform_rank = false, partial_order = false;
			GetNumber(name2val, std::string("rank_size"), rank_size, args_count, size_t(0) );
			GetBool(name2val, "uniform_rank", uniform_rank, args_count);
			GetBool(name2val, "partial_order", partial_order, args_count);

			if(!partial_order)
			{
				LOG4CXX_INFO(logger, "--- Using normal rank builder with uniform_rank=" << uniform_rank);
				return weights::RankBuilderPtr( new weights::NormalRankBuilder(pMatrix, rank_size, uniform_rank) );
			}
			else
			{
				std::string partial_type = "rounding";
				bool sports_order = false;
				bool idf = false;
				double idf_strength = 1.0;

				GetBool(name2val, "idf", idf, args_count);
				GetNumber(name2val, "idf_strength", idf_strength, args_count);
				GetBool(name2val, "sports_order", sports_order, args_count);
				GetStrLower(name2val, "partial_type", partial_type, args_count);

				if(partial_type == "rounding" )
				{
					double div_factor = 10.0;
					GetNumber(name2val, "div_factor", div_factor, args_count);

					LOG4CXX_INFO(logger, "--- Using rounding rank builder with div_factor=" << div_factor
								 << ", sports_order=" << sports_order  << ", uniform_rank=" << uniform_rank
								 << ", idf=" << idf << ", idf_strenght=" << idf_strength);

					return weights::RankBuilderPtr( new weights::RoundingBasedPartialOrder(pMatrix, rank_size, uniform_rank,
													       div_factor, sports_order, idf, idf_strength) );
				}
				else
					throw std::runtime_error( "Unknown partial type: " + partial_type );

			}
			LOG4CXX_WARN(logger, "------ Something is wrong! why i am here????? ");
			return weights::RankBuilderPtr( new weights::NormalRankBuilder(pMatrix, rank_size, uniform_rank) );
		}// CreateRankBuilder

		weights::RankBuilderPtr FunctionFactory::CreateRankBuilder(const std::string &args, Matrices::SuperMatrixPtr pMatrix, size_t &args_count)
		{
			STR2STR name2val;
			PrepareArgs(args, name2val);

			return CreateRankBuilder(name2val, pMatrix, args_count);
		}

		std::string FunctionFactory::CreateRankBuilderString(STR2STR &name2val, Matrices::SuperMatrixPtr pMatrix, size_t &args_count)
		{
			std::string rank_size = "350";
			std::string uniform_rank = "false";
			bool partial_order = false;
			GetString(name2val, std::string("rank_size"), rank_size, args_count);
			GetString(name2val, "uniform_rank", uniform_rank, args_count);
			GetBool(name2val, "partial_order", partial_order, args_count);

			if(!partial_order)
			{
				LOG4CXX_INFO(logger, "--- Using normal rank builder with uniform_rank=" << uniform_rank);
				std::string rstr = "normal(";
				rstr+= "uniform_rank=" + uniform_rank;
				rstr+= ",rank_size=" + rank_size;
				rstr+= ")";
				return rstr;
			}
			else
			{
				std::string partial_type = "rounding";
				std::string sports_order = "false";
				std::string idf = "false";
				std::string idf_strength = "1.0";

				GetString(name2val, "idf", idf, args_count);
				GetString(name2val, "idf_strength", idf_strength, args_count);
				GetString(name2val, "sports_order", sports_order, args_count);
				GetStrLower(name2val, "partial_type", partial_type, args_count);

				if(partial_type == "rounding" )
				{
					std::string div_factor = "10.0";
					GetString(name2val, "div_factor", div_factor, args_count);

					LOG4CXX_INFO(logger, "--- Using rounding rank builder with div_factor=" << div_factor
								 << ", sports_order=" << sports_order  << ", uniform_rank=" << uniform_rank
								 << ", idf=" << idf << ", idf_strenght=" << idf_strength);
					std::string rstr;
					rstr = "rounding_partial(";
					rstr += "divide_factor=" + div_factor;
					rstr += ",sport_ranking=" + sports_order;
					rstr += ",uniform_rank=" + uniform_rank;
					rstr += ",idf=" + idf;
					rstr += ",idf_strength=" + idf_strength;
					rstr += ")";
					return rstr;
				}
				else
					throw std::runtime_error( "Unknown partial type: " + partial_type );
			}
		}

		std::string FunctionFactory::CreateRankBuilderString(const std::string &args, Matrices::SuperMatrixPtr pMatrix, size_t &args_count)
		{
			STR2STR name2val;
			PrepareArgs(args, name2val);

			return CreateRankBuilderString(name2val, pMatrix, args_count);
		}

		CompareFunctionPtr FunctionFactory::CreatePMIQuantified(STR2STR &name2val, Matrices::SuperMatrixPtr pMatrix)
		{
			std::string discount = "true";
			size_t args_count = 0;

			GetString(name2val, "discount", discount, args_count);

			if ( args_count != name2val.size())
				throw std::runtime_error("Some arguments were unparsed in PMI.");

			LOG4CXX_INFO(logger,"Created pmi quantified with: discount: " << discount);

			std::string weigherStr = "MI_simple(discount=" + discount + ")";

			std::string simStr = "cosine()";

			std::string cmpStr = "cmp(weight=" + weigherStr + ",simfunction=" + simStr + ")";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

			//return CompareFunctionPtr( new smartcomparator::compare::PMIQuantifiedComparision( pMatrix, discount ) );
		}//CreatePMIQuantified

		CompareFunctionPtr FunctionFactory::CreatePMI(STR2STR &name2val, Matrices::SuperMatrixPtr pMatrix)
		{
			std::string discount = "true";
			std::string threshold="0";
			size_t args_count = 0;

			GetString(name2val, "discount", discount, args_count);
			GetString(name2val, "threshold", threshold, args_count);

			if ( args_count != name2val.size())
				throw std::runtime_error("Some arguments were unparsed in PMI.");

			LOG4CXX_INFO(logger,"Created pmi with: discount: " << discount);

			std::string weigherStr = "MI_simple(discount=" + discount + ")";
			std::string simStr = "cosine()";

			std::string cmpStr = "cmp(weight=" + weigherStr + ",simfunction=" + simStr + ")";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

			//return CompareFunctionPtr( new smartcomparator::compare::PMIComparision( pMatrix, discount, threshold ) );
		}//CreatePMI



		CompareFunctionPtr FunctionFactory::CreateLogEnt(const std::string &args, Matrices::SuperMatrixPtr pMatrix)
		{
			LOG4CXX_INFO(logger, "Creating LOGENT function with args: " << args );

			std::map<std::string, std::string> name2value;
			PrepareArgs(args, name2value);

			simfunctions::SimilarityFunctionPtr cos( new simfunctions::CosineFunction(pMatrix) );
			weights::WeightFeaturePtr weight(new weights::LogEntWeight(pMatrix));
			if(0 != name2value.size() )
				throw std::runtime_error( "Some arguments where unparsed in logent");
			//return CompareFunctionPtr( new CompareFunction( pMatrix, filters::FilterFeaturePtr(),
			//selectors::SelectorPtr(), weight ,cos));

			std::string weigherStr = "logent()";
			std::string simStr = "cosine()";
			std::string cmpStr = "cmp(weight=" + weigherStr + ",simfunction=" + simStr + ")";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);
		}

		CompareFunctionPtr FunctionFactory::CreateSHD(const std::string &args, Matrices::SuperMatrixPtr pMatrix)
		{
			LOG4CXX_INFO(logger, "Creating SHD function with args: " << args);
			std::string alpha = "0.5";
			std::string rank_size = "350", mintf = "5";
			std::string rz = "2.57", noise="0.99";
			std::string uniform_rank = "true";
			std::map<std::string, std::string> name2value;
			PrepareArgs(args, name2value);

			size_t args_count = 0;
			if( GetUniformRank(name2value, uniform_rank) )
				args_count++;
			if( GetRankSize(name2value, rank_size) )
				args_count++;
			//if( GetColMintf(name2value, mintf) )
			//	args_count++;
			if( GetNoise(name2value, noise) )
				args_count++;
			GetString(name2value, "rz", rz, args_count);
			GetString(name2value, "alpha", alpha, args_count);
			GetString(name2value, "mintf", mintf, args_count);
			if(args_count != name2value.size() )
				throw std::runtime_error( "Some arguments where unparsed in: " + args );

			LOG4CXX_INFO(logger, "Created SHD(alpha = " << alpha << "), using RWFZscore with rank-size: " << rank_size << ", mintf: " << mintf << ", noise: " << noise
						 << ", uniform_rank: " << uniform_rank );

			std::string cNoise = boost::lexical_cast<std::string> ((size_t) (pMatrix->NumberOfColumns() * boost::lexical_cast<double>(noise)));
			std::string filterStr = "noisektf(k=" + cNoise + ",mintf=" + mintf + ")";

			std::string rankStr = "normal(rank_size=" + rank_size + ",uniform_rank=" + uniform_rank + ")";
			std::string weigherStr = "rwf_zscore(rankbuilder=" + rankStr + ",threshold=" + rz + ")";

			std::string simStr = "shd(alpha=" + alpha + ")";

			std::string cmpStr = "cmp(weight=" + weigherStr + ",filter=" + filterStr + ",simfunction=" + simStr + ")";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

			//return CompareFunctionPtr( new SHDComparision( pMatrix, alpha, rank_size, noise, mintf, rz, uniform_rank) );
		}

		CompareFunctionPtr FunctionFactory::CreateTfIdf(Matrices::SuperMatrixPtr pMatrix)
		{
			LOG4CXX_INFO(logger, "Crating plain cosine function...");
			simfunctions::SimilarityFunctionPtr cos( new simfunctions::CosineFunction(pMatrix, true) );
			weights::WeightFeaturePtr tfidf( new weights::TfidfNormalizeWeight(pMatrix) );

			std::string simStr = "cosine()";
			std::string weigherStr = "tfidf()";

			std::string cmpStr = "cmp(weight=" + weigherStr + ",simfunction=" + simStr + ")";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

			/*return CompareFunctionPtr( new CompareFunction( pMatrix, filters::FilterFeaturePtr(),
															selectors::SelectorPtr(), tfidf,
															cos ));
			*/
		}
		CompareFunctionPtr FunctionFactory::CreateCosine(const std::string &args, Matrices::SuperMatrixPtr pMatrix)
		{
			LOG4CXX_INFO(logger, "Crating plain cosine function...");
			//simfunctions::CosineFunction *cos = new simfunctions::CosineFunction(pMatrix);
			std::string cmpStr = "cmp(simfunction=cosine())";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

			//return CompareFunctionPtr( new CompareFunction( pMatrix, filters::FilterFeaturePtr(),
		}

		CompareFunctionPtr FunctionFactory::CreateDice(const std::string &args, Matrices::SuperMatrixPtr pMatrix)
		{
			LOG4CXX_INFO(logger, "Crating Dice coefficient function...");
			//simfunctions::Dice *dice = new simfunctions::Dice(pMatrix);

			std::string cmpStr = "cmp(simfunction=dice())";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

			//return CompareFunctionPtr( new CompareFunction( pMatrix, filters::FilterFeaturePtr(),
			//                                                                     selectors::SelectorPtr(), weights::WeightFeaturePtr(),
			//                                                                                                simfunctions::SimilarityFunctionPtr(dice) ));
		}

		 CompareFunctionPtr FunctionFactory::CreateJaccard(const std::string &args, Matrices::SuperMatrixPtr pMatrix)
		{
			LOG4CXX_INFO(logger, "Crating Jaccard coeficcient function..." );

			std::string cmpStr = "cmp(simfunction=jaccard())";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

			//simfunctions::Jaccard *jac = new simfunctions::Jaccard(pMatrix);
			//return CompareFunctionPtr( new CompareFunction( pMatrix, filters::FilterFeaturePtr(),
			//                                                                     selectors::SelectorPtr(), weights::WeightFeaturePtr(),
			//					    simfunctions::SimilarityFunctionPtr(jac) ));
		}

		CompareFunctionPtr FunctionFactory::CreateRWFNoWeight(STR2STR &name2val, Matrices::SuperMatrixPtr pMatrix)
		{
			size_t args_count = 0;
			std::string col_mintf = "5";
			std::string noisePrec = "0.99", threshold = "0";

			std::string row_minnz; // those are initialized in GetRowFreqFilter
			std::string row_mintf;
			std::string row_minTF;
			GetRowFreqFilter(name2val, row_mintf, row_minTF, row_minnz, args_count);

			GetString(name2val, "colmintf", col_mintf,  args_count);
                        GetString(name2val, "noise", noisePrec, args_count);
			GetString(name2val, "threshold", threshold, args_count);


			std::string rankStr = CreateRankBuilderString(name2val, pMatrix, args_count);

			if ( args_count != name2val.size())
				throw std::runtime_error("Some aguments were unparsed in CreateRWFNoWeight");

			LOG4CXX_INFO(logger,"Creating rwf lin function with params: " << "noise: " << noisePrec << ", col_mintf: "
						 << col_mintf << ", treshold: " << threshold << ", row_mintf: " << row_mintf << ", row_minnz: "
						 << row_minnz << ", row_minTF:" << row_minTF);

			std::string cNoise = boost::lexical_cast<std::string> ((size_t) (pMatrix->NumberOfColumns() * boost::lexical_cast<double>(noisePrec)));
			std::string filterStr = "noisektf(k=" + cNoise + ",mintf=" + col_mintf + ")";

			std::string selectorStr = "frequency(min_nz=" + row_minnz + ",min_tf=" + row_mintf + ",min_TF=" + row_minTF + ")";

			std::string weigherStr = "rwf_noweight(rankbuilder=" + rankStr + ")";

			std::string simStr = "cosine()";

			std::string cmpStr = "cmp(weight=" + weigherStr + ",selector=" + selectorStr + ",simfunction=" + simStr +
					     ",filter=" + filterStr + ")";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

			//return CompareFunctionPtr(new RWFNoWeightCosComparison(pMatrix, pRankBuilder, noisePrec, col_mintf,
			//													  threshold, row_minnz, row_mintf, row_minTF) );
		}
		CompareFunctionPtr FunctionFactory::CreateQuantifiedCos(STR2STR & name2val, Matrices::SuperMatrixPtr pMatrix)
		{
			size_t args_count = 0;
			std::string col_mintf = "5";
			std::string trail = "2";
			std::string include_zeros = "false";
			std::string noisePrec = "0.99", threshold = "0";

			std::string row_minnz; // those are initialized in GetRowFreqFilter
			std::string row_mintf;
			std::string row_minTF;
			GetRowFreqFilter(name2val, row_mintf, row_minTF, row_minnz, args_count);

			GetString(name2val, "colmintf", col_mintf,  args_count);
			GetString(name2val, "noise", noisePrec, args_count);
			GetString(name2val, "threshold", threshold, args_count);
			GetString(name2val, "trail", trail, args_count);
			GetString(name2val, "include_zeros", include_zeros, args_count);

			if ( args_count != name2val.size())
				throw std::runtime_error("Some aguments were unparsed in CreateQuantifiedCos");

			LOG4CXX_INFO(logger, "Creating quantified cos function with params: " << "noise: " << noisePrec << ", col_mintf: "
						 << col_mintf << ", treshold: " << threshold << ", row_mintf: " << row_mintf << ", row_minnz: "
						 << row_minnz << ", row_minTF:" << row_minTF);

			std::string cNoise = boost::lexical_cast<std::string> ((size_t) (pMatrix->NumberOfColumns() * boost::lexical_cast<double>(noisePrec)));
			std::string filterStr = "noisektf(k=" + cNoise + ",mintf=" + col_mintf + ")";

			std::string selectorStr = "frequency(min_nz=" + row_minnz + ",min_tf=" + row_mintf + ",min_TF=" + row_minTF + ")";

			std::string weigherStr = "MI_quant(miFilter="+ threshold + ",trail=" + trail + ",include_zeros=" + include_zeros + ")";

			std::string simStr = "cosine()";

			std::string cmpStr = "cmp(weight=" + weigherStr + ",selector=" + selectorStr + ",simfunction=" + simStr +
					     ",filter=" + filterStr + ")";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);
			//return CompareFunctionPtr(new QuantifiedMICosComparison(pMatrix, noisePrec, col_mintf,
			//threshold, row_minnz, row_mintf, row_minTF, trail, include_zeros) );
		}
		CompareFunctionPtr FunctionFactory::CreateQuantifiedLin(STR2STR & name2val, Matrices::SuperMatrixPtr pMatrix)
		{
			size_t args_count = 0;
			std::string col_mintf = "5";
			std::string trail = "2";
			std::string include_zeros = "false";
			std::string noisePrec = "0.99", threshold = "0";

			std::string row_minnz; // those are initialized in GetRowFreqFilter
			std::string row_mintf;
			std::string row_minTF;
			GetRowFreqFilter(name2val, row_mintf, row_minTF, row_minnz, args_count);

			GetString(name2val, "colmintf", col_mintf,  args_count);
			GetString(name2val, "noise", noisePrec, args_count);
			GetString(name2val, "threshold", threshold, args_count);
			GetString(name2val, "trail", trail, args_count);
			GetString(name2val, "include_zeros", include_zeros, args_count);

			if ( args_count != name2val.size())
				throw std::runtime_error("Some aguments were unparsed in CreateQuantifiedLin");

			LOG4CXX_INFO(logger, "Creating quantified lin function with params: " << "noise: " << noisePrec << ", col_mintf: "
						 << col_mintf << ", treshold: " << threshold << ", row_mintf: " << row_mintf << ", row_minnz: "
						 << row_minnz << ", row_minTF:" << row_minTF);

			std::string cNoise = boost::lexical_cast<std::string> ((size_t) (pMatrix->NumberOfColumns() * boost::lexical_cast<double>(noisePrec)));
			std::string filterStr = "noisektf(k=" + cNoise + ",mintf=" + col_mintf + ")";

			std::string selectorStr = "frequency(min_nz=" + row_minnz + ",min_tf=" + row_mintf + ",min_TF=" + row_minTF + ")";

			std::string weigherStr = "MI_quant(miFilter="+ threshold + ",trail=" + trail + ",include_zeros=" + include_zeros + ")";

			std::string simStr = "lin()";

			std::string cmpStr = "cmp(weight=" + weigherStr + ",selector=" + selectorStr + ",simfunction=" + simStr +
					     ",filter=" + filterStr + ")";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);
			//return CompareFunctionPtr(new QuantifiedMILinComparison(pMatrix, noisePrec, col_mintf,
			//													  threshold, row_minnz, row_mintf, row_minTF) );
		}

		CompareFunctionPtr FunctionFactory::CreatePlainSimpleLin(const std::string &args,Matrices::SuperMatrixPtr pMatrix)
		{
			LOG4CXX_INFO(logger, "Creating (simple) plain Lin's compare function");
			std::string cmpStr = "cmp(simfunction=lin())";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);
			//return CompareFunctionPtr( new CompareFunction(pMatrix, filters::FilterFeaturePtr(),
			//											   selectors::SelectorPtr(),weights::WeightFeaturePtr(),
			//											   simfunctions::SimilarityFunctionPtr( new smartcomparator::simfunctions::LinSimilarity(pMatrix))) );
		}//CreatePlainLin

		CompareFunctionPtr FunctionFactory::CreateCRMDMI(const std::string &args,Matrices::SuperMatrixPtr pMatrix)
		{
			LOG4CXX_INFO(logger, "Creating crm_dmi function, using args: " << args);
			bool noise_filter = false;
			std::string filter_prec = "0.95";
			std::string mintf = "5";
			bool use_tscore_selector = false;
			std::string tscore_treshold = "2.567";

			size_t args_count = 0;
			std::map<std::string, std::string> name2value;
			PrepareArgs(args, name2value);

			if( GetColMintf(name2value, mintf) )
				args_count++;
			if( GetNoise(name2value, filter_prec) )
				args_count++;
			if( GetUseNoiseFilter(name2value, noise_filter) )
				args_count++;
			if( GetUseTScoreSelector(name2value, use_tscore_selector) )
				args_count++;
			if( GetTScoreTreshold(name2value, tscore_treshold) )
				args_count++;
			if(args_count != name2value.size() )
				throw std::runtime_error( "Some arguments where unparsed in: " + args );

			LOG4CXX_INFO(logger, "About to create crm_dmi, args parsed: use_noise: "<< noise_filter << ", noise: " << filter_prec
						 << ", mintf: " << mintf << ", use_tscore_selector: " << use_tscore_selector << ", t_treshold = " << tscore_treshold);

			std::string simStr = "crm()";

			std::string weigherStr = "CRmDmi()";

			std::string cmpStr = "cmp(simfunction=" + simStr + ",weight=" + weigherStr;

			if (noise_filter)
			{
				std::string cNoise = boost::lexical_cast<std::string> ((size_t) (pMatrix->NumberOfColumns() * boost::lexical_cast<double>(filter_prec)));
				cmpStr += ",filter=noisektff(k=" + cNoise + ",mintf=" + mintf + ")";
			}
			if (use_tscore_selector)
			{
				cmpStr +=",selector=TScore(threshold=" + tscore_treshold + ")";
			}
			cmpStr += ")";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

			//return CompareFunctionPtr( new smartcomparator::compare::CRMDmiComparision( pMatrix, noise_filter, filter_prec,
			//																			(int) mintf, use_tscore_selector, tscore_treshold ) );

		}//CreateCRMDMI

		CompareFunctionPtr FunctionFactory::CreateMILin(STR2STR & name2val, const std::string &args, Matrices::SuperMatrixPtr pMatrix)
		{
			size_t args_count = 0;
			std::string mi_threshold = "0";
			GetString(name2val, "threshold", mi_threshold, args_count);
			if ( args_count != name2val.size())
				throw std::runtime_error("Some aguments were unparsed in CreateMILin");

			LOG4CXX_INFO(logger, "Creating simple Lin's MI compare function... Args: " << args);
			//MILinsComparision *pFun = new MILinsComparision( pMatrix);

			std::string weigherStr = "MI(miFilter=" + mi_threshold +")";

			std::string simStr = "lin()";

			std::string cmpStr = "cmp(weight=" + weigherStr + ",simfunction=" + simStr + ")";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

			//return CompareFunctionPtr( new MILinsComparision( pMatrix, mi_threshold) );
		}//CreateMILin

		CompareFunctionPtr FunctionFactory::CreateMILinCosine(STR2STR & name2val, const std::string &args, Matrices::SuperMatrixPtr pMatrix)
		{
			size_t args_count = 0;
			std::string mi_threshold = "0";
			GetString(name2val, "threshold", mi_threshold, args_count);
			if ( args_count != name2val.size())
				throw std::runtime_error("Some aguments were unparsed in CreateMILin");

			LOG4CXX_INFO(logger, "Creating simple Lin's MI compare function, using cosine similarity... Args: " << args);

			std::string weigherStr = "MI(miFilter=" + mi_threshold + ")";

			std::string simStr = "cosine()";

			std::string cmpStr = "cmp(weight=" + weigherStr + ",simfunction=" + simStr + ")";

			FunctionFactory2 f;
			return f.CreateComparator(cmpStr, pMatrix);

			//return CompareFunctionPtr( new MILinCosComparision( pMatrix, mi_threshold) );
		}//CreateMILinCosine

		CompareFunctionPtr FunctionFactory::CreateRWFLinEnsemble(STR2STR & name2val, Matrices::SuperMatrixPtr pMatrix)
		{
			//ensemble initialization
			std::vector<CompareFunctionPtr> comparators;
			std::vector<double> weights;
			std::map<std::string, Matrices::SuperMatrixPtr> boundaryMap;
			Matrices::SuperMatrixSplitter::splitMatrix(pMatrix, boundaryMap);
			double AdjP_w = 0.8;
			double AmISubj_w = 0.6;
			double Coord_w = 0.8;
			double NGen_w = 0.6;

			//RWF Lin initialization
			size_t args_count = 0;
			int col_mintf = 5;
			double noisePrec = 0.99, threshold = 0;
			size_t row_minnz; // those are initialized in GetRowFreqFilter
			size_t row_mintf;
			size_t row_minTF;
			GetRowFreqFilter(name2val, row_mintf, row_minTF, row_minnz, args_count);

			GetNumber(name2val, "colmintf", col_mintf,  args_count, 0);
			GetNumber(name2val, "noise", noisePrec, args_count,0.0, 1.0);
			GetNumber(name2val, "threshold", threshold, args_count);
			weights::RankBuilderPtr pRankBuilder = CreateRankBuilder(name2val, pMatrix, args_count);

			if(boundaryMap.find("substAdjP_utf") != boundaryMap.end())
			{
				if (name2val.find("AdjP_w") != name2val.end())
					AdjP_w = boost::lexical_cast<double>(name2val["AdjP_w"]);
				comparators.push_back(CompareFunctionPtr(new RWFMILinComparision(boundaryMap["substAdjP_utf"], pRankBuilder,
												 noisePrec, col_mintf,
												 threshold, row_minnz, row_mintf, row_minTF) ));
				weights.push_back(AdjP_w);
			}
			if(boundaryMap.find("substAmISubj") != boundaryMap.end())
			{
				if (name2val.find("AmISubj_w") != name2val.end())
					AmISubj_w = boost::lexical_cast<double>(name2val["AmISubj_w"]);
				comparators.push_back(CompareFunctionPtr(new RWFMILinComparision(boundaryMap["substAmISubj"], pRankBuilder,
												 noisePrec, col_mintf,
												 threshold, row_minnz, row_mintf, row_minTF) ));
				weights.push_back(AmISubj_w);
			}
			if(boundaryMap.find("substCoord") != boundaryMap.end())
			{
				if (name2val.find("Coord_w") != name2val.end())
					AdjP_w = boost::lexical_cast<double>(name2val["Coord_w"]);
				comparators.push_back(CompareFunctionPtr(new RWFMILinComparision(boundaryMap["substCoord"], pRankBuilder,
												 noisePrec, col_mintf,
												 threshold, row_minnz, row_mintf, row_minTF) ));
				weights.push_back(Coord_w);
			}
			if(boundaryMap.find("substNGen") != boundaryMap.end())
			{
				if (name2val.find("NGen_w") != name2val.end())
					NGen_w = boost::lexical_cast<double>(name2val["NGen_w"]);
				comparators.push_back(CompareFunctionPtr(new RWFMILinComparision(boundaryMap["substNGen"], pRankBuilder,
												 noisePrec, col_mintf,
												 threshold, row_minnz, row_mintf, row_minTF) ));
				weights.push_back(NGen_w);
			}

			return CompareFunctionPtr(new EnsembleCompareFunction(comparators, weights));
		}

		CompareFunctionPtr FunctionFactory::CreateRWFLinScaled(STR2STR &name2val, Matrices::SuperMatrixPtr pMatrix)
		{
			size_t args_count = 0;
			int col_mintf = 5;
			double noisePrec = 0.99, threshold = 0;

			size_t row_minnz; // those are initialized in GetRowFreqFilter
			size_t row_mintf;
			size_t row_minTF;
			GetRowFreqFilter(name2val, row_mintf, row_minTF, row_minnz, args_count);

			GetNumber(name2val, "colmintf", col_mintf,  args_count, 0);
			GetNumber(name2val, "noise", noisePrec, args_count,0.0, 1.0);
			GetNumber(name2val, "threshold", threshold, args_count);

			size_t divfactor = 1000;
			GetRankSize(name2val, divfactor);
			divfactor /= 10;


			weights::RankBuilderPtr pRankBuilder = CreateRankBuilder(name2val, pMatrix, args_count);

			if ( args_count != name2val.size())
				throw std::runtime_error("Some aguments were unparsed in CreateRWFLinScaled");

			LOG4CXX_INFO(logger, "Creating rwf lin function with params: " << "noise: " << noisePrec << ", col_mintf: "
						 << col_mintf << ", treshold: " << threshold << ", row_mintf: " << row_mintf << ", row_minnz: "
						 << row_minnz << ", row_minTF:" << row_minTF);

			return CompareFunctionPtr(new RWFLinScaledComparison(pMatrix, pRankBuilder, noisePrec, col_mintf,
									     threshold, row_minnz, row_mintf, row_minTF, divfactor) );
		}//CreateRWFLinScaled

		bool FunctionFactory::GetUniformRank(std::map<std::string, std::string> &name2val, bool &uniform_rank)
		{
			if( name2val.find("uniform_rank") == name2val.end() )
				return false;
			std::string val = name2val["uniform_rank"];
			boost::to_lower(val);
			if( val == "false" )
				uniform_rank = false;
			else if( val == "true")
				uniform_rank = true;
			else
				throw std::runtime_error("Unknow value for 'uniform_rank': " + name2val["uniform_rank"]);
			return true;
		}//GetUniformRank

		bool FunctionFactory::GetDiscount(std::map<std::string, std::string> &name2val, bool &discount)
		{
			if( name2val.find("discount") == name2val.end() )
				return false;
			std::string val = name2val["discount"];
			boost::to_lower(val);
			if( val == "false" )
				discount = false;
			else if( val == "true")
				discount = true;
			else
				throw std::runtime_error("Unknow value for 'discount': " + name2val["discount"]);
			return true;
		}//GetDiscount

		bool FunctionFactory::GetRankSize(std::map<std::string, std::string> &name2val, size_t &rank_size)
		{
			if( name2val.find("rank_size") == name2val.end() )
				return false;
			rank_size = boost::lexical_cast<size_t> ( name2val["rank_size"] );
			return true;
		}//GetRankSize

		bool FunctionFactory::GetColMintf(std::map<std::string, std::string> &name2val, size_t &min_tf)
		{
			if( name2val.find("colmintf") == name2val.end() )
				return false;
			min_tf = boost::lexical_cast<size_t> ( name2val["colmintf"] );
			return true;
		}//GetColMinTf

		bool FunctionFactory::GetRz(std::map<std::string, std::string> &name2val, double &rz)
		{
			if( name2val.find("rz") == name2val.end() )
				return false;
			rz = boost::lexical_cast<double> ( name2val["rz"] );
			return true;
		}//GetRz

		bool FunctionFactory::GetMinCDFP(std::map<std::string, std::string> &name2val, double &min_cdf_p)
		{
			if( name2val.find("min_cdf_p") == name2val.end() )
				return false;
			min_cdf_p = boost::lexical_cast<double> ( name2val["min_cdf_p"] );
			if(min_cdf_p < 0 || min_cdf_p >= 1)
				throw std::runtime_error("min_cdf_p has to be in range <0,1)");
			return true;
		}//GetMinCDFP

		bool FunctionFactory::GetTreshold(std::map<std::string, std::string> &name2val, double &treshold)
		{
			if( name2val.find("treshold") == name2val.end() )
				return false;
			treshold = boost::lexical_cast<double> ( name2val["tscore"] );
			return true;
		}//GetTreshold

		bool FunctionFactory::GetTScoreTreshold(std::map<std::string, std::string> &name2val, double &treshold)
		{
			if( name2val.find("tscore") == name2val.end() )
				return false;
			treshold = boost::lexical_cast<double> ( name2val["tscore"] );
			if(treshold <= 0)
				throw std::runtime_error("tscore has to be > 0");
			return true;
		}//GetTScoreTreshold

		bool FunctionFactory::GetNoise(std::map<std::string, std::string> &name2val, double &noise)
		{
			if( name2val.find("noise") == name2val.end() )
				return false;
			noise = boost::lexical_cast<double> ( name2val["noise"] );
			if(noise < 0 || noise >= 1)
				throw std::runtime_error("noise has to be in <0,1]");
			return true;
		}//GetNoise

		bool FunctionFactory::GetPNorm(STR2STR &name2val, double &p_norm)
		{
			if( name2val.find("p-norm") == name2val.end() )
				return false;
			p_norm = boost::lexical_cast<double> ( name2val["p-norm"] );
			if(p_norm < 1)
				throw std::runtime_error("p-norm has to be >=1");
			return true;
		}//GetPNorm
		bool FunctionFactory::GetUseNoiseFilter(std::map<std::string, std::string> &name2val, bool &noise_filter)
		{
			if( name2val.find("use_noise") == name2val.end() )
				return false;
			std::string val = name2val["use_noise"];
			boost::to_lower(val);
			if( val == "false" )
				noise_filter = false;
			else if( val == "true")
				noise_filter = true;
			else
				throw std::runtime_error("Unknow value for 'discount': " + name2val["discount"]);
			return true;
		}
		bool FunctionFactory::GetUseTScoreSelector(std::map<std::string, std::string> &name2val, bool &tsc_sel)
		{
			if( name2val.find("use_tscore_selector") == name2val.end() )
				return false;
			std::string val = name2val["use_tscore_selector"];
			boost::to_lower(val);
			if( val == "false" )
				tsc_sel = false;
			else if( val == "true")
				tsc_sel = true;
			else
				throw std::runtime_error("Unknow value for 'discount': " + name2val["discount"]);
			return true;
		}

		void FunctionFactory::GetRowFreqFilter(STR2STR &name2val, size_t &row_mintf,
						       size_t &row_minTF, size_t &row_minnz, size_t &args_count)
		{
			row_mintf = 0;
			row_minTF = 0;
			row_minnz = 0;

			GetNumber(name2val, "row_mintf", row_mintf, args_count);
			GetNumber(name2val, "row_minTF", row_minTF, args_count);
			GetNumber(name2val, "row_minnz", row_minnz, args_count);

		}
		void FunctionFactory::PrepareArgs(const std::string &args, std::map<std::string, std::string> & name2val)
		{
			std::string copy = args;
			boost::trim(copy);
			if(copy.length() != 0)
			{
				std::vector<std::string> arg_tokens;
				boost::split(arg_tokens, copy, boost::is_any_of(",") );
				for(size_t i = 0; i < arg_tokens.size(); i++)
				{
					boost::trim( arg_tokens[i] );
					if( arg_tokens[i].length() )
					{
						std::vector<std::string> vName2val;
						boost::split(vName2val, arg_tokens[i], boost::is_any_of("=") );
						if( vName2val.size() != 2 )
							throw std::runtime_error("Wrong format of argumets " + args + ", wrong entry: " + arg_tokens[i] );
						std::string name = vName2val[0];
						std::string value = vName2val[1];
						boost::trim(name);
						boost::trim(value);
						if(name.length() == 0 || value.length() == 0)
							throw std::runtime_error("Wrong format of argumets " + args + ", wrong entry: " + arg_tokens[i] );
						name2val[name] = value;
					}//if arg_tokens[i].length != 0
				}// for each argument
			}//if copy.lengt > 0
		}//PrepareArgs
		bool FunctionFactory::GetUniformRank(std::map<std::string, std::string> &name2val, std::string &uniform_rank)
		{
			if( name2val.find("uniform_rank") == name2val.end() )
				return false;
			std::string val = name2val["uniform_rank"];
			boost::to_lower(val);
			if( val == "false" )
				uniform_rank = "false";
			else if( val == "true")
				uniform_rank = "true";
			else
				throw std::runtime_error("Unknow value for 'uniform_rank': " + name2val["uniform_rank"]);
			return true;
		}//GetUniformRank

		bool FunctionFactory::GetDiscount(std::map<std::string, std::string> &name2val, std::string &discount)
		{
			if( name2val.find("discount") == name2val.end() )
				return false;
			std::string val = name2val["discount"];
			boost::to_lower(val);
			if( val == "false" )
				discount = "false";
			else if( val == "true")
				discount = "true";
			else
				throw std::runtime_error("Unknow value for 'discount': " + name2val["discount"]);
			return true;
		}//GetDiscount

		bool FunctionFactory::GetRankSize(std::map<std::string, std::string> &name2val, std::string &rank_size)
		{
			if( name2val.find("rank_size") == name2val.end() )
				return false;
			rank_size = ( name2val["rank_size"] );
			return true;
		}//GetRankSize

		bool FunctionFactory::GetColMintf(std::map<std::string, std::string> &name2val, std::string &min_tf)
		{
			if( name2val.find("colmintf") == name2val.end() )
				return false;
			min_tf = boost::lexical_cast<size_t> ( name2val["colmintf"] );
			return true;
		}//GetColMinTf

		bool FunctionFactory::GetRz(std::map<std::string, std::string> &name2val, std::string &rz)
		{
			if( name2val.find("rz") == name2val.end() )
				return false;
			rz = ( name2val["rz"] );
			return true;
		}//GetRz

		bool FunctionFactory::GetMinCDFP(std::map<std::string, std::string> &name2val, std::string &min_cdf_p)
		{
			if( name2val.find("min_cdf_p") == name2val.end() )
				return false;
			min_cdf_p = ( name2val["min_cdf_p"] );
			return true;
		}//GetMinCDFP

		bool FunctionFactory::GetTreshold(std::map<std::string, std::string> &name2val, std::string &treshold)
		{
			if( name2val.find("treshold") == name2val.end() )
				return false;
			treshold = ( name2val["tscore"] );
			return true;
		}//GetTreshold

		bool FunctionFactory::GetTScoreTreshold(std::map<std::string, std::string> &name2val, std::string &treshold)
		{
			if( name2val.find("tscore") == name2val.end() )
				return false;
			treshold = ( name2val["tscore"] );
			return true;
		}//GetTScoreTreshold

		bool FunctionFactory::GetNoise(std::map<std::string, std::string> &name2val, std::string &noise)
		{
			if( name2val.find("noise") == name2val.end() )
				return false;
			noise = ( name2val["noise"] );
			return true;
		}//GetNoise

		bool FunctionFactory::GetPNorm(STR2STR &name2val, std::string &p_norm)
		{
			if( name2val.find("p-norm") == name2val.end() )
				return false;
			p_norm = ( name2val["p-norm"] );
			return true;
		}//GetPNorm
		bool FunctionFactory::GetUseNoiseFilter(std::map<std::string, std::string> &name2val, std::string &noise_filter)
		{
			if( name2val.find("use_noise") == name2val.end() )
				return false;
			std::string val = name2val["use_noise"];
			boost::to_lower(val);
			if( val == "false" )
				noise_filter = "false";
			else if( val == "true")
				noise_filter = "true";
			else
				throw std::runtime_error("Unknow value for 'discount': " + name2val["discount"]);
			return true;
		}
		bool FunctionFactory::GetUseTScoreSelector(std::map<std::string, std::string> &name2val, std::string &tsc_sel)
		{
			if( name2val.find("use_tscore_selector") == name2val.end() )
				return false;
			std::string val = name2val["use_tscore_selector"];
			boost::to_lower(val);
			if( val == "false" )
				tsc_sel = "false";
			else if( val == "true")
				tsc_sel = "true";
			else
				throw std::runtime_error("Unknow value for 'discount': " + name2val["discount"]);
			return true;
		}

		void FunctionFactory::GetRowFreqFilter(STR2STR &name2val, std::string &row_mintf,
						       std::string &row_minTF, std::string &row_minnz, size_t &args_count)
		{
			row_mintf = "0";
			row_minTF = "0";
			row_minnz = "0";

			GetString(name2val, "row_mintf", row_mintf, args_count);
			GetString(name2val, "row_minTF", row_minTF, args_count);
			GetString(name2val, "row_minnz", row_minnz, args_count);

		}

	}//compare

}//smartcomparator

