/*
    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 <boost/algorithm/string/erase.hpp>
#include <boost/filesystem.hpp>
#include "FunctionFactory2.h"

#include "../simfunctions/partialmsr/DBManagerMySQL.h"

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

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

		void GetStr2(STR2STR &name2val, const std::string& name, std::string &result)
		{
			if( name2val.find(name) != name2val.end() )
			{
				result = name2val[name];

			}
		}

		void GetStrLower2(STR2STR &name2val, const std::string& name, std::string &result)
		{
			if( name2val.find(name) != name2val.end() )
			{
				result = name2val[name];
				boost::to_lower(result);
			}
		}
		void GetBool2(STR2STR &name2val, const std::string& name, bool &result)
		{
			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("Unknown value for '"+name+"': " + name2val[name] +
								 " expected boolean ('true' or 'false')");
			}
		}

		/**
		 * \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 GetNumber2(STR2STR &name2val, const std::string& name, T &result ,
		T lower_bound = real_min2<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(name + " out of range");
			}
		}

		FunctionFactory2::FunctionFactory2()
		{
			initComparators();
			initFilters();
			initSelectors();
			initSimfunctions();
			initLocalSimfunctions();
			initRankBuilders();
			initWeights();
			initRowRelativeSelectors();
			initDistfunctions();
			initTransformations();
		}

		void FunctionFactory2::initComparators()
		{
			legal_comparator_args.push_back("weight");
			legal_comparator_args.push_back("selector");
			legal_comparator_args.push_back("relative_selector");
			legal_comparator_args.push_back("simfunction");
			legal_comparator_args.push_back("filter");
			legal_comparator_args.push_back("transformation");
			legal_ensemble_args.push_back("comparator");
			legal_ensemble_args.push_back("cmp_weight");
		}

		void FunctionFactory2::initFilters()
		{
			initFilterFeature01();
			initFilterVector();
			initNoiseKFilter();
			initNoiseKTFFilter();
			initEntropyFilter();
		}
		void FunctionFactory2::initFilterFeature01()
		{
			std::vector<std::string> args;
			args.push_back("k");
			legal_filter_args["feature01"] = args;
			filter_functions["feature01"] = &smartcomparator::compare::FunctionFactory2::CreateFilterFeature01;
		}
		void FunctionFactory2::initFilterVector()
		{
			std::vector<std::string> args;
			args.push_back("filter");
			legal_filter_args["vector"] = args;
			filter_functions["vector"] = &smartcomparator::compare::FunctionFactory2::CreateFilterVector;
		}
		void FunctionFactory2::initNoiseKTFFilter()
		{
			std::vector<std::string> args;
			args.push_back("k");
			args.push_back("mintf");
			legal_filter_args["noisektf"] = args;
			filter_functions["noisektf"] = &smartcomparator::compare::FunctionFactory2::CreateFilterNoiseKTF;
		}

		void FunctionFactory2::initNoiseKFilter()
		{
			std::vector<std::string> args;
			args.push_back("k");
			legal_filter_args["noisek"] = args;
			filter_functions["noisek"] = &smartcomparator::compare::FunctionFactory2::CreateFilterNoiseK;
		}

		void FunctionFactory2::initEntropyFilter()
		{
			std::vector<std::string> args;
			args.push_back("to_remove");
			args.push_back("remove_zeros");
			legal_filter_args["entropy"] = args;
			filter_functions["entropy"] = &smartcomparator::compare::FunctionFactory2::CreateEntropyFilter;
		}

		void FunctionFactory2::initSelectors()
		{
			initFrequencySelector();
			initTScoreSelector();
			initTScoreKBestSelector();
			initRFFSelector();
		}
		void FunctionFactory2::initFrequencySelector()
		{
			std::vector<std::string> args;
			args.push_back("min_nz");
			args.push_back("min_tf");
			args.push_back("min_TF");
			legal_selector_args["frequency"] = args;
			selector_functions["frequency"] = &smartcomparator::compare::FunctionFactory2::CreateSelectorFrequency;
		}
		void FunctionFactory2::initTScoreSelector()
		{
			std::vector<std::string> args;
			args.push_back("threshold");
			legal_selector_args["TScore"] = args;
			selector_functions["TScore"] = &smartcomparator::compare::FunctionFactory2::CreateSelectorTScore;
		}
		void FunctionFactory2::initTScoreKBestSelector()
		{
			std::vector<std::string> args;
			args.push_back("threshold");
			args.push_back("k");
			legal_selector_args["TScoreKBest"] = args;
			selector_functions["TScoreKBest"] = &smartcomparator::compare::FunctionFactory2::CreateSelectorTScoreKBest;
		}
		void FunctionFactory2::initRFFSelector()
		{
			std::vector<std::string> args;
			args.push_back("TFThreshold");
			args.push_back("weightThreshold");
			legal_selector_args["RFF"] = args;
			selector_functions["RFF"] = &smartcomparator::compare::FunctionFactory2::CreateSelectorRFF;
		}

		void FunctionFactory2::initSimfunctions()
		{
			initSimfunctionCosine();
			initSimfunctionCosineFilter();
			initSimfunctionCRM();
			initSimfunctionDice();
			initSimfunctionDiceBugged();
			initSimfunctionEhlert();
			initSimfunctionFile();
			initSimfunctionJaccard();
			initSimfunctionLin();
			initSimfunctionMCF();
			initSimfunctionPEntP();
			initSimfunctionSHD();
			initSimfunctionDistance();
			initSimfunctionRatio();
			initSimfunctionIntersectionScaled();
			initSimfunctionPartialMSR();
			initSimfunctionPartialMSR2A();
			initSimfunctionPartialMSR2B();
			initSimfunctionPartialMSR2Bp();
			initSimfunctionBhattacharyya();
		}
		void FunctionFactory2::initSimfunctionCosine()
		{
			std::vector<std::string> args;
			args.push_back("matrixNormalized");
			legal_simfunction_args["cosine"] = args;
			simfunctions_functions["cosine"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionCosine;
		}
		void FunctionFactory2::initSimfunctionCosineFilter()
		{
			std::vector<std::string> args;
			args.push_back("percentIter");
			args.push_back("minIter");
			legal_simfunction_args["cosinefilter"] = args;
			simfunctions_functions["cosinefilter"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionCosineFilter;
		}
		void FunctionFactory2::initSimfunctionCRM()
		{
			std::vector<std::string> args;
			args.push_back("gamma");
			args.push_back("beta");
			legal_simfunction_args["crm"] = args;
			simfunctions_functions["crm"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionCRM;
		}
		void FunctionFactory2::initSimfunctionDice()
		{
			std::vector<std::string> args;
			legal_simfunction_args["dice"] = args;
			simfunctions_functions["dice"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionDice;
		}
		void FunctionFactory2::initSimfunctionDiceBugged()
		{
			std::vector<std::string> args;
			args.push_back("power");
			args.push_back("normalize");
			legal_simfunction_args["dice_bugged"] = args;
			simfunctions_functions["dice_bugged"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionDiceBugged;
		}
		void FunctionFactory2::initSimfunctionEhlert()
		{
			std::vector<std::string> args;
			args.push_back("delta");
			args.push_back("gamma");
			args.push_back("alpha");
			legal_simfunction_args["ehlert"] = args;
			simfunctions_functions["ehlert"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionEhlert;
		}
		void FunctionFactory2::initSimfunctionFile()
		{
			std::vector<std::string> args;
			args.push_back("sim_matrix");
			legal_simfunction_args["filesim"] = args;
			simfunctions_functions["filesim"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionFile;
		}
		void FunctionFactory2::initSimfunctionJaccard()
		{
			std::vector<std::string> args;
			legal_simfunction_args["jaccard"] = args;
			simfunctions_functions["jaccard"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionJaccard;
		}
		void FunctionFactory2::initSimfunctionLin()
		{
			std::vector<std::string> args;
			legal_simfunction_args["lin"] = args;
			simfunctions_functions["lin"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionLin;
		}
		void FunctionFactory2::initSimfunctionMCF()
		{
			std::vector<std::string> args;
			args.push_back("sim_inner");
			args.push_back("weight");
			args.push_back("threshold");
			legal_simfunction_args["mcf"] = args;
			simfunctions_functions["mcf"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionMCF;

		}
		void FunctionFactory2::initSimfunctionPEntP()
		{
			std::vector<std::string> args;
			legal_simfunction_args["pentp"] = args;
			simfunctions_functions["pentp"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionPEntP;
		}
		void FunctionFactory2::initSimfunctionSHD()
		{
			std::vector<std::string> args;
			args.push_back("alpha");
			legal_simfunction_args["shd"] = args;
			simfunctions_functions["shd"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionSHD;
		}
		void FunctionFactory2::initSimfunctionDistance()
		{
			std::vector<std::string> args;
			args.push_back("dist");
			legal_simfunction_args["distancesim"] = args;
			simfunctions_functions["distancesim"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionDistance;
		}
		void FunctionFactory2::initSimfunctionRatio()
		{
			std::vector<std::string> args;
			legal_simfunction_args["ratio"] = args;
			simfunctions_functions["ratio"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionRatio;
		}
		void FunctionFactory2::initSimfunctionIntersectionScaled()
		{
			std::vector<std::string> args;
			args.push_back("sim_inner");
			args.push_back("countVals");
			legal_simfunction_args["intersection_scaled"] = args;
			simfunctions_functions["intersection_scaled"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionIntersectionScaled;
		}
		void FunctionFactory2::initSimfunctionPartialMSR()
		{
			std::vector<std::string> args;
			args.push_back("sim_inner");
			args.push_back("bad_features_file");
			args.push_back("freq_supermatrix_dir");
			args.push_back("freq_supermatrix_name");
			legal_simfunction_args["partial_msr"] = args;
			simfunctions_functions["partial_msr"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionPartialMSR;
		}
		void FunctionFactory2::initParamsForPartialMSR2( std::vector<std::string>& pParams )
		{
			pParams.push_back("freq_supermatrix_dir");
			pParams.push_back("freq_supermatrix_name");
			pParams.push_back("db_host");
			pParams.push_back("db_port");
			pParams.push_back("db_name");
			pParams.push_back("db_user");
			pParams.push_back("db_pass");
			pParams.push_back("db_language");
			pParams.push_back("param_min_tree_equality");
			pParams.push_back("param_classes");
			pParams.push_back("param_weight_inner");
			pParams.push_back("param_sim_inner");
			pParams.push_back("param_features_percent_to_remove");
			pParams.push_back("param_min_feature_weight_for_lemma");
		}
		void FunctionFactory2::initSimfunctionPartialMSR2A()
		{
			std::vector<std::string> args;
			initParamsForPartialMSR2( args );
			args.push_back("param_k");
			legal_simfunction_args["partial_msr2_a"] = args;
			simfunctions_functions["partial_msr2_a"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionPartialMSR2A;
		}
		void FunctionFactory2::initSimfunctionPartialMSR2B()
		{
			std::vector<std::string> args;
			initParamsForPartialMSR2( args );
			args.push_back("param_k");
			args.push_back("param_n");
			legal_simfunction_args["partial_msr2_b"] = args;
			simfunctions_functions["partial_msr2_b"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionPartialMSR2B;
		}
		void FunctionFactory2::initSimfunctionPartialMSR2Bp()
		{
			std::vector<std::string> args;
			initParamsForPartialMSR2( args );
			args.push_back("param_k");
			args.push_back("param_n");
			legal_simfunction_args["partial_msr2_bp"] = args;
			simfunctions_functions["partial_msr2_bp"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionPartialMSR2Bp;
		}
		void FunctionFactory2::initSimfunctionBhattacharyya()
		{
			std::vector<std::string> args;
			args.push_back("matrixNormalized");
			legal_simfunction_args["bhattacharyya"] = args;
			simfunctions_functions["bhattacharyya"] = &smartcomparator::compare::FunctionFactory2::CreateSimfunctionBhattacharyya;
		}

		void FunctionFactory2::initLocalSimfunctions()
		{
			initLocalSimfunctionLocalCosine();
			initLocalSimfunctionIRad();
		}
		void FunctionFactory2::initLocalSimfunctionLocalCosine()
		{
			std::vector<std::string> args;
			args.push_back("isNormalized");
			args.push_back("doFilter");
			args.push_back("percentInter");
			args.push_back("minInter");
			legal_localsimfunction_args["local_cosine"] = args;
			localsimfunctions_functions["local_cosine"] = &smartcomparator::compare::FunctionFactory2::CreateLocalSimfunctionLocalCosine;
		}

		void FunctionFactory2::initLocalSimfunctionIRad()
		{
			std::vector<std::string> args;
			args.push_back("beta");
			args.push_back("weight");
			legal_localsimfunction_args["irad"] = args;
			localsimfunctions_functions["irad"] = &smartcomparator::compare::FunctionFactory2::CreateLocalSimfunctionIRad;
		}

		void FunctionFactory2::initDistfunctions()
		{
			initDistfunctionMinkowski();
			initDistfunctionEuclid();
		}

		void FunctionFactory2::initDistfunctionMinkowski()
		{
			std::vector<std::string> args;
			args.push_back("p");
			legal_distfunction_args["minkowski"] = args;
			distfunctions_functions["minkowski"] = &smartcomparator::compare::FunctionFactory2::CreateDistfunctionMinkowski;
		}
		void FunctionFactory2::initDistfunctionEuclid()
		{
			std::vector<std::string> args;
			legal_distfunction_args["euclid"] = args;
			distfunctions_functions["euclid"] = &smartcomparator::compare::FunctionFactory2::CreateDistfunctionEuclid;
		}

		void FunctionFactory2::initWeights()
		{
			initWeightCRMDt();
			initWeightCRmDmi();
			initWeightIdf();
			initWeightLogEntNormalize();
			initWeightLogEnt();
			initWeightMI();
			initWeightMIQuantified();
			initWeightMLE();
			initWeightNormalize();
			initWeightRFF();
			initWeightRWF();
			initWeightRWFChi2();
			initWeightRWFEvertsMI();
			initWeightRWFLinFiltered();
			initWeightRWFLin();
			initWeightRWFLogLikelihood();
			initWeightRWFNoWeight();
			initWeightRWFPMI();
			initWeightRWFZScore();
			initWeightRWFZScoreLocal();
			initWeightRWFZScoreInMatrix();
			initWeightSimpleMI();
			initWeightTScore();
			initWeightTfidfNormalize();
			initWeightTfidf();
			initWeightRowScaled();
			initWeightColumnScaled();
			initWeightBoundaryScaled();
			initWeightQuantify();
			initWeightPMINoLog();
			initWeightLogLikelihood();
			initWeightZScore();
			initWeightZScoreLocal();
			initWeightZScoreMatrix();
			initWeightEvertsMI();
			initWeightChi2();
			initWeightBeta();
			initWeightFirstKulczynsky();
			initWeightUnigramSubtuples();
			initWeightSCost();
		}
		void FunctionFactory2::initWeightCRMDt()
		{
			std::vector<std::string> args;
			legal_weigher_args["CRMDt"] = args;
			weight_functions["CRMDt"] = &smartcomparator::compare::FunctionFactory2::CreateWeightCRMDt;

		}
		void FunctionFactory2::initWeightCRmDmi()
		{
			std::vector<std::string> args;
			legal_weigher_args["CRmDmi"] = args;
			weight_functions["CRmDmi"] = &smartcomparator::compare::FunctionFactory2::CreateWeightCRmDmi;
		}
		void FunctionFactory2::initWeightIdf()
		{
			std::vector<std::string> args;
			legal_weigher_args["idf"] = args;
			weight_functions["idf"] = &smartcomparator::compare::FunctionFactory2::CreateWeightIdf;
		}
		void FunctionFactory2::initWeightLogEntNormalize()
		{
			std::vector<std::string> args;
			args.push_back("useFilteredEntropy");
			legal_weigher_args["logent_normalize"] = args;
			weight_functions["logent_normalize"] = &smartcomparator::compare::FunctionFactory2::CreateWeightLogEntNormalize;
		}
		void FunctionFactory2::initWeightLogEnt()
		{
			std::vector<std::string> args;
			args.push_back("useFilteredEntropy");
			legal_weigher_args["logent"] = args;
			weight_functions["logent"] = &smartcomparator::compare::FunctionFactory2::CreateWeightLogEnt;
		}
		void FunctionFactory2::initWeightMI()
		{
			std::vector<std::string> args;
			args.push_back("miFilter");
			legal_weigher_args["MI"] = args;
			weight_functions["MI"] = &smartcomparator::compare::FunctionFactory2::CreateWeightMI;
		}
		void FunctionFactory2::initWeightMIQuantified()
		{
			std::vector<std::string> args;
			args.push_back("miFilter");
			args.push_back("trail");
			args.push_back("include_zeros");
			legal_weigher_args["MI_quant"] = args;
			weight_functions["MI_quant"] = &smartcomparator::compare::FunctionFactory2::CreateWeightMIQuantified;
		}
		void FunctionFactory2::initWeightMLE()
		{
			std::vector<std::string> args;
			legal_weigher_args["MLE"] = args;
			weight_functions["MLE"] = &smartcomparator::compare::FunctionFactory2::CreateWeightMLE;
		}
		void FunctionFactory2::initWeightNormalize()
		{
			std::vector<std::string> args;
			legal_weigher_args["normalize"] = args;
			weight_functions["normalize"] = &smartcomparator::compare::FunctionFactory2::CreateWeightNormalize;
		}
		void FunctionFactory2::initWeightRFF()
		{
			std::vector<std::string> args;
			args.push_back("simmatrix");
			args.push_back("top_k");
			args.push_back("sim_threshold");
			args.push_back("selector");
			legal_weigher_args["rff"] = args;
			weight_functions["rff"] = &smartcomparator::compare::FunctionFactory2::CreateWeightRFF;
		}
		void FunctionFactory2::initWeightRWF()
		{
			std::vector<std::string> args;
			args.push_back("rankbuilder");
			args.push_back("weight_inner");
			legal_weigher_args["rwf"] = args;
			weight_functions["rwf"] = &smartcomparator::compare::FunctionFactory2::CreateWeightRWF;
		}
		void FunctionFactory2::initWeightRWFChi2()
		{
			std::vector<std::string> args;
			args.push_back("rankbuilder");
			args.push_back("threshold");
			legal_weigher_args["rwf_chi2"] = args;
			weight_functions["rwf_chi2"] = &smartcomparator::compare::FunctionFactory2::CreateWeightRWFChi2;
		}
		void FunctionFactory2::initWeightRWFEvertsMI()
		{
			std::vector<std::string> args;
			args.push_back("rankbuilder");
			args.push_back("mi_threshold");
			legal_weigher_args["rwf_evertsmi"] = args;
			weight_functions["rwf_evertsmi"] = &smartcomparator::compare::FunctionFactory2::CreateWeightRWFEvertsMI;
		}
		void FunctionFactory2::initWeightRWFLin()
		{
			std::vector<std::string> args;
			args.push_back("rankbuilder");
			args.push_back("threshold");
			legal_weigher_args["rwf_lin"] = args;
			weight_functions["rwf_lin"] = &smartcomparator::compare::FunctionFactory2::CreateWeightRWFLin;
		}
		void FunctionFactory2::initWeightRWFLinFiltered()
		{
			std::vector<std::string> args;
			args.push_back("rankbuilder");
			args.push_back("threshold");
			legal_weigher_args["rwf_lin_filtered"] = args;
			weight_functions["rwf_lin_filtered"] = &smartcomparator::compare::FunctionFactory2::CreateWeightRWFLinFiltered;
		}
		void FunctionFactory2::initWeightRWFLogLikelihood()
		{
			std::vector<std::string> args;
			args.push_back("rankbuilder");
			args.push_back("threshold");
			legal_weigher_args["rwf_log"] = args;
			weight_functions["rwf_log"] = &smartcomparator::compare::FunctionFactory2::CreateWeightRWFLogLikelihood;
		}
		void FunctionFactory2::initWeightRWFNoWeight()
		{
			std::vector<std::string> args;
			args.push_back("rankbuilder");
			legal_weigher_args["rwf_noweight"] = args;
			weight_functions["rwf_noweight"] = &smartcomparator::compare::FunctionFactory2::CreateWeightRWFNoWeight;
		}
		void FunctionFactory2::initWeightRWFPMI()
		{
			std::vector<std::string> args;
			args.push_back("rankbuilder");
			args.push_back("discount");
			args.push_back("threshold");
			legal_weigher_args["rwf_pmi"] = args;
			weight_functions["rwf_pmi"] = &smartcomparator::compare::FunctionFactory2::CreateWeightRWFPMI;
		}
		void FunctionFactory2::initWeightRWFZScore()
		{
			std::vector<std::string> args;
			args.push_back("rankbuilder");
			args.push_back("threshold");
			legal_weigher_args["rwf_zscore"] = args;
			weight_functions["rwf_zscore"] = &smartcomparator::compare::FunctionFactory2::CreateWeightRWFZScore;
		}
		void FunctionFactory2::initWeightRWFZScoreInMatrix()
		{
			std::vector<std::string> args;
			args.push_back("rankbuilder");
			args.push_back("threshold");
			legal_weigher_args["rwf_zscore_in_matrix"] = args;
			weight_functions["rwf_zscore_in_matrix"] = &smartcomparator::compare::FunctionFactory2::CreateWeightRWFZScoreInMatrix;
		}
		void FunctionFactory2::initWeightRWFZScoreLocal()
		{
			std::vector<std::string> args;
			args.push_back("rankbuilder");
			args.push_back("threshold");
			legal_weigher_args["rwf_zscore_local"] = args;
			weight_functions["rwf_zscore_local"] = &smartcomparator::compare::FunctionFactory2::CreateWeightRWFZScoreLocal;
		}
		void FunctionFactory2::initWeightSimpleMI()
		{
			std::vector<std::string> args;
			args.push_back("discount");
			args.push_back("mi_threshold");
			legal_weigher_args["MI_simple"] = args;
			weight_functions["MI_simple"] = &smartcomparator::compare::FunctionFactory2::CreateWeightSimpleMI;
		}
		void FunctionFactory2::initWeightPMINoLog()
		{
			std::vector<std::string> args;
			args.push_back("discount");
			args.push_back("mi_threshold");
			legal_weigher_args["pmi_nolog"] = args;
			weight_functions["pmi_nolog"] = &smartcomparator::compare::FunctionFactory2::CreateWeightPMINoLog;
		}
		void FunctionFactory2::initWeightTScore()
		{
			std::vector<std::string> args;
			legal_weigher_args["TScore"] = args;
			weight_functions["TScore"] = &smartcomparator::compare::FunctionFactory2::CreateWeightTScore;
		}
		void FunctionFactory2::initWeightTfidfNormalize()
		{
			std::vector<std::string> args;
			legal_weigher_args["tfidf_normalize"] = args;
			weight_functions["tfidf_normalize"] = &smartcomparator::compare::FunctionFactory2::CreateWeightTfidfNormalize;
		}
		void FunctionFactory2::initWeightTfidf()
		{
			std::vector<std::string> args;
			legal_weigher_args["tfidf"] = args;
			weight_functions["tfidf"] = &smartcomparator::compare::FunctionFactory2::CreateWeightTfidf;
		}
		void FunctionFactory2::initWeightRowScaled()
		{
			std::vector<std::string> args;
			args.push_back("weight_inner");
			legal_weigher_args["row_scaled"] = args;
			weight_functions["row_scaled"] = &smartcomparator::compare::FunctionFactory2::CreateWeightRowScaled;
		}
		void FunctionFactory2::initWeightColumnScaled()
		{
			std::vector<std::string> args;
			args.push_back("weight_inner");
			legal_weigher_args["column_scaled"] = args;
			weight_functions["column_scaled"] = &smartcomparator::compare::FunctionFactory2::CreateWeightColumnScaled;
		}
		void FunctionFactory2::initWeightBoundaryScaled()
		{
			std::vector<std::string> args;
			args.push_back("AdjP");
			args.push_back("AmISubj");
			args.push_back("Coord");
			args.push_back("NGen");
			args.push_back("weight_inner");
			legal_weigher_args["boundary_scaled"] = args;
			weight_functions["boundary_scaled"] = &smartcomparator::compare::FunctionFactory2::CreateWeightBoundaryScaled;
		}
		void FunctionFactory2::initWeightQuantify()
		{
			std::vector<std::string> args;
			args.push_back("trailing_digits");
			args.push_back("zeros");
			args.push_back("weight_inner");
			legal_weigher_args["quant"] = args;
			weight_functions["quant"] = &smartcomparator::compare::FunctionFactory2::CreateWeightQuantify;
		}
		void FunctionFactory2::initWeightLogLikelihood()
		{
			std::vector<std::string> args;
			args.push_back("threshold");
			legal_weigher_args["loglikelihood"] = args;
			weight_functions["loglikelihood"] = &smartcomparator::compare::FunctionFactory2::CreateWeightLogLikelihood;
		}
		void FunctionFactory2::initWeightZScore()
		{
			std::vector<std::string> args;
			args.push_back("threshold");
			legal_weigher_args["zscore"] = args;
			weight_functions["zscore"] = &smartcomparator::compare::FunctionFactory2::CreateWeightZScore;
		}
		void FunctionFactory2::initWeightZScoreLocal()
		{
			std::vector<std::string> args;
			args.push_back("threshold");
			legal_weigher_args["zscore_local"] = args;
			weight_functions["zscore_local"] = &smartcomparator::compare::FunctionFactory2::CreateWeightZScoreLocal;
		}
		void FunctionFactory2::initWeightZScoreMatrix()
		{
			std::vector<std::string> args;
			args.push_back("threshold");
			legal_weigher_args["zscore_in_matrix"] = args;
			weight_functions["zscore_in_matrix"] = &smartcomparator::compare::FunctionFactory2::CreateWeightZScoreMatrix;
		}
		void FunctionFactory2::initWeightChi2()
		{
			std::vector<std::string> args;
			args.push_back("threshold");
			legal_weigher_args["chi2"] = args;
			weight_functions["chi2"] = &smartcomparator::compare::FunctionFactory2::CreateWeightChi2;
		}
		void FunctionFactory2::initWeightEvertsMI()
		{
			std::vector<std::string> args;
			args.push_back("threshold");
			legal_weigher_args["evertsmi"] = args;
			weight_functions["evertsmi"] = &smartcomparator::compare::FunctionFactory2::CreateWeightEvertsMI;
		}
		void FunctionFactory2::initWeightBeta()
		{
			std::vector<std::string> args;
			args.push_back("q");
			args.push_back("r");
			args.push_back("s");
			args.push_back("t");
			args.push_back("params");
			args.push_back("modifier");
			legal_weigher_args["beta"] = args;
			weight_functions["beta"] = &smartcomparator::compare::FunctionFactory2::CreateWeightBeta;
		}
		void FunctionFactory2::initWeightFirstKulczynsky()
		{
			std::vector<std::string> args;
			args.push_back("threshold");
			legal_weigher_args["first_kulczynsky"] = args;
			weight_functions["first_kulczynsky"] = &smartcomparator::compare::FunctionFactory2::CreateWeightChi2;
		}
		void FunctionFactory2::initWeightUnigramSubtuples()
		{
			std::vector<std::string> args;
			args.push_back("threshold");
			legal_weigher_args["unigram_subtuples"] = args;
			weight_functions["unigram_subtuples"] = &smartcomparator::compare::FunctionFactory2::CreateWeightChi2;
		}
		void FunctionFactory2::initWeightSCost()
		{
			std::vector<std::string> args;
			args.push_back("threshold");
			legal_weigher_args["scost"] = args;
			weight_functions["scost"] = &smartcomparator::compare::FunctionFactory2::CreateWeightChi2;
		}


		void FunctionFactory2::initRankBuilders()
		{
			initRankNormal();
			initRankPartial();
			initRankRoundingBasedPartial();
		}
		void FunctionFactory2::initRankNormal()
		{
			std::vector<std::string> args;
			args.push_back("uniform_rank");
			args.push_back("rank_size");
			legal_rank_args["normal"] = args;
			rank_functions["normal"] = &smartcomparator::compare::FunctionFactory2::CreateRankNormal;
		}
		void FunctionFactory2::initRankPartial()
		{
			std::vector<std::string> args;
			args.push_back("uniform_rank");
			args.push_back("rank_size");
			args.push_back("sport_ranking");
			args.push_back("idf");
			args.push_back("idf_strength");
			legal_rank_args["partial"] = args;
			rank_functions["partial"] = &smartcomparator::compare::FunctionFactory2::CreateRankPartial;
		}
		void FunctionFactory2::initRankRoundingBasedPartial()
		{
			std::vector<std::string> args;
			args.push_back("uniform_rank");
			args.push_back("rank_size");
			args.push_back("sport_ranking");
			args.push_back("idf");
			args.push_back("idf_strength");
			args.push_back("divide_factor");
			legal_rank_args["rounding_partial"] = args;
			rank_functions["rounding_partial"] = &smartcomparator::compare::FunctionFactory2::CreateRankRoundingBasedPartial;
		}

		void FunctionFactory2::initRowRelativeSelectors()
		{
			initRowRelativeSelectorTScoreKBest();
		}
		void FunctionFactory2::initRowRelativeSelectorTScoreKBest()
		{
			std::vector<std::string> args;
			args.push_back("tscore_threshold");
			legal_relativeselector_args["TScoreKBest"] = args;
			relativeselector_functions["TScoreKBest"] = &smartcomparator::compare::FunctionFactory2::CreateRowRelativeSelectorTScoreKBest;
		}

		void FunctionFactory2::initLocalWeights()
		{
			initLocalWeightLogEnt();
		}
		void FunctionFactory2::initLocalWeightLogEnt()
		{
			std::vector<std::string> args;
			args.push_back("useFilteredEntropy");
			legal_localweigher_args["logent"] = args;
			localweight_functions["logent"] = &smartcomparator::compare::FunctionFactory2::CreateLocalWeightLogEnt;
		}

		void FunctionFactory2::initTransformations()
		{
			initSVDTransformation();
			initTransformationLDA();
		}
		void FunctionFactory2::initSVDTransformation()
		{
			std::vector<std::string> args;
			args.push_back("dimensions");
			legal_transformation_args["SVD"] = args;
			transformation_functions["SVD"] = &smartcomparator::compare::FunctionFactory2::CreateTransformationSVD;
		}
		void FunctionFactory2::initTransformationLDA()
		{
			std::vector<std::string> args;
			args.push_back("num_topics");
			args.push_back("passes");
			args.push_back("temp_dir");
			legal_transformation_args["LDA"] = args;
			transformation_functions["LDA"] = &smartcomparator::compare::FunctionFactory2::CreateTransformationLDA;
		}


		filters::FilterFeaturePtr FunctionFactory2::CreateFilter(const std::string& filter_str,
									 Matrices::SuperMatrixPtr matrix)
		{
			std::map<std::string,std::string> args;
			std::string namestr, argstr;
			getNameAndArgs(filter_str, namestr, argstr);
			if (filter_functions.find(namestr) == filter_functions.end())
				throw std::runtime_error("Unknown filter identifier: " + namestr);
			PrepareArgs(argstr, args, namestr, legal_filter_args[namestr]);
			if (filter_functions.find(namestr) != filter_functions.end())
				return filter_functions[namestr](this, args, matrix);

			throw std::runtime_error("Unknown filter identifier: " + namestr);
		}

		filters::FilterFeaturePtr FunctionFactory2::CreateFilterFeature01(std::map<std::string, std::string> & args,
										  Matrices::SuperMatrixPtr matrix)
		{
			size_t k = 2;
			if (args.find("k") != args.end())
				GetNumber2(args, "k", k);
			return filters::FilterFeaturePtr(new filters::FilterFeature01(matrix->GetColumnFeatures(),k));
		}
		filters::FilterFeaturePtr FunctionFactory2::CreateFilterVector(std::map<std::string, std::string> & args,
									       Matrices::SuperMatrixPtr matrix)
		{
			std::vector<std::string> filters;

			if (args.find("filter") != args.end())
				filters.push_back(args["filter"]);
			else
				throw std::runtime_error("Filter vector must not be empty (missing required filter argument)");
			size_t i = 1;
			std::string argname = "filter1";
			while(args.find(argname) != args.end())
			{
				filters.push_back(args[argname]);
				i++;
				argname="filter"+boost::lexical_cast<std::string>(i);
			}
			filters::FilterVector* retptr =(new filters::FilterVector(matrix->GetColumnFeatures()));
			for (size_t j=0; j<filters.size(); j++)
			{
				retptr->AddFilter(CreateFilter(filters[j], matrix).get());
			}
			return filters::FilterFeaturePtr(retptr);
		}
		filters::FilterFeaturePtr FunctionFactory2::CreateFilterNoiseKTF(std::map<std::string, std::string> & args,
										 Matrices::SuperMatrixPtr matrix)
		{
			size_t k;
			size_t mintf = 2;
			if (args.find("mintf") != args.end())
				GetNumber2(args, "mintf", mintf);
			if (args.find("k") != args.end())
				GetNumber2(args, "k", k);
			else
				throw std::runtime_error("Noise filter missing required argument: k");
			return filters::FilterFeaturePtr(new filters::NoiseKTFFilter(matrix->GetColumnFeatures(), k, mintf));
		}
		filters::FilterFeaturePtr FunctionFactory2::CreateFilterNoiseK(std::map<std::string, std::string> & args,
									       Matrices::SuperMatrixPtr matrix)
		{
			size_t k=0;
			if (args.find("k") != args.end())
				GetNumber2(args, "k", k);
			else
				throw std::runtime_error("Noise filter missing required argument: k");

			return filters::FilterFeaturePtr(new filters::NoiseKFilter(matrix->GetColumnFeatures(), k));
		}
		filters::FilterFeaturePtr FunctionFactory2::CreateEntropyFilter(std::map<std::string, std::string> & args,
								 Matrices::SuperMatrixPtr matrix)
		{
			bool remove_zeros = true;
			double prec2remove = 0.1;
			if (args.find("to_remove") != args.end())
				GetNumber2(args, "to_remove", prec2remove);
			else
				throw std::runtime_error("Entropy filter missing required argument: to_remove");
			if (args.find("remove_zeros") != args.end())
				GetBool2(args, "remove_zeros", remove_zeros);


			return filters::FilterFeaturePtr(new filters::EntropyFilter(matrix->GetColumnFeatures(), prec2remove, remove_zeros));
		}

		selectors::SelectorPtr FunctionFactory2::CreateSelector(const std::string& selector_str,
									Matrices::SuperMatrixPtr matrix)
		{
			std::map<std::string,std::string> args;
			std::string namestr, argstr;
			getNameAndArgs(selector_str, namestr, argstr);
			if (selector_functions.find(namestr) == selector_functions.end())
				throw std::runtime_error("Unknown selector identifier: " + namestr);
			PrepareArgs(argstr, args, namestr, legal_selector_args[namestr]);
			if (selector_functions.find(namestr) != selector_functions.end())
			{
				return selector_functions[namestr](this, args, matrix);
			}
			throw std::runtime_error("Unknown selector identifier: " + namestr);
		}

		selectors::SelectorPtr FunctionFactory2::CreateSelectorFrequency(std::map<std::string, std::string> & args,
										 Matrices::SuperMatrixPtr matrix)
		{
			size_t min_nz = 0;
			size_t min_tf = 0;
			size_t min_TF = 0;
			if (args.find("min_nz") != args.end())
				GetNumber2(args, "min_nz", min_nz);
			if (args.find("min_tf") != args.end())
				GetNumber2(args, "min_tf", min_tf);
			if (args.find("min_TF") != args.end())
				GetNumber2(args, "min_TF", min_TF);
			return selectors::SelectorPtr(new selectors::FrequencySelector(matrix, min_nz, min_tf, min_TF));
		}
		selectors::SelectorPtr FunctionFactory2::CreateSelectorTScore(std::map<std::string, std::string> & args,
									      Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 2.576;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			return selectors::SelectorPtr(new selectors::TScoreSelector(matrix, threshold));
		}
		selectors::SelectorPtr FunctionFactory2::CreateSelectorTScoreKBest(std::map<std::string, std::string> & args,
										   Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 2.576;
			size_t k = 350;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			if (args.find("k") != args.end())
				GetNumber2(args, "k", k);
			return selectors::SelectorPtr(new selectors::TScoreKBestSelector(matrix, k, threshold));
		}
		selectors::SelectorPtr FunctionFactory2::CreateSelectorRFF(std::map<std::string, std::string> & args,
									   Matrices::SuperMatrixPtr matrix)
		{
			size_t TFThreshold;
			double weightThreshold;
			if (args.find("TFThreshold") != args.end())
				GetNumber2(args, "TFThreshold", TFThreshold);
			else
				throw std::runtime_error("RFF selector missing required argument: TFThreshold");
			if (args.find("weightThreshold") != args.end())
				GetNumber2(args, "weightThreshold", weightThreshold);
			else
				throw std::runtime_error("RFF selector missing required argument: weightThreshold");
			return selectors::SelectorPtr(new selectors::RFFSelector(matrix, TFThreshold, weightThreshold));
		}
		selectors::RFFSelectorPtr FunctionFactory2::RFFCreateSelectorRFF(std::map<std::string, std::string> & args,
										 Matrices::SuperMatrixPtr matrix)
		{
			size_t TFThreshold;
			double weightThreshold;
			if (args.find("TFThreshold") != args.end())
				GetNumber2(args, "TFThreshold", TFThreshold);
			else
				throw std::runtime_error("RFF selector missing required argument: TFThreshold");
			if (args.find("weightThreshold") != args.end())
				GetNumber2(args, "weightThreshold", weightThreshold);
			else
				throw std::runtime_error("RFF selector missing required argument: weightThreshold");
			return selectors::RFFSelectorPtr(new selectors::RFFSelector(matrix, TFThreshold, weightThreshold));
		}

		selectors::RowRelativeSelectorPtr FunctionFactory2::CreateRowRelativeSelector(const std::string& relativeselector_str,
											      Matrices::SuperMatrixPtr matrix)
		{
			std::map<std::string,std::string> args;
			std::string namestr, argstr;
			getNameAndArgs(relativeselector_str, namestr, argstr);
			if (relativeselector_functions.find(namestr) == relativeselector_functions.end())
				throw std::runtime_error("Unknown relative selector identifier: " + namestr);
			PrepareArgs(argstr, args, namestr, legal_relativeselector_args[namestr]);
			if (relativeselector_functions.find(namestr) != relativeselector_functions.end())
			{
				return relativeselector_functions[namestr](this, args, matrix);
			}
			throw std::runtime_error("Unknown relative selector identifier: " + namestr);
		}
		selectors::RowRelativeSelectorPtr FunctionFactory2::CreateRowRelativeSelectorTScoreKBest(std::map<std::string, std::string> & args,
													 Matrices::SuperMatrixPtr matrix)
		{
			double tscore_threshold;
			if (args.find("tscore_threshold") != args.end())
				GetNumber2(args, "tscore_threshold", tscore_threshold);
			else
				throw std::runtime_error("Relative T Score K Best selector missing required argument: tscore_threshold");
			throw std::runtime_error("Relative T Score K Best selector is not yet supported and cannot be instantiated.");
			//return selectors::RowRelativeSelectorPtr(new selectors::RelativeTScoreKBestSelector(matrix, tscore_threshold));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeigher(const std::string& weigher_str,
									  Matrices::SuperMatrixPtr matrix)
		{
			std::map<std::string,std::string> args;
			std::string namestr, argstr;
			getNameAndArgs(weigher_str, namestr, argstr);
			if (weight_functions.find(namestr) == weight_functions.end())
				throw std::runtime_error("Unknown weigher function identifier: " + namestr);
			PrepareArgs(argstr, args, namestr, legal_weigher_args[namestr]);
			if (weight_functions.find(namestr) != weight_functions.end())
			{
				return weight_functions[namestr](this, args, matrix);
			}
			throw std::runtime_error("Unknown weigher function identifier: " + namestr);
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightCRMDt(std::map<std::string, std::string> & args,
									      Matrices::SuperMatrixPtr matrix)
		{
			return weights::WeightFeaturePtr(new weights::CRmDt(matrix));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightCRmDmi(std::map<std::string, std::string> & args,
									       Matrices::SuperMatrixPtr matrix)
		{
			return weights::WeightFeaturePtr(new weights::CRmDmi(matrix));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightIdf(std::map<std::string, std::string> & args,
									      Matrices::SuperMatrixPtr matrix)
		{
			return weights::WeightFeaturePtr(new weights::IdfWeight(matrix));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightLogEnt(std::map<std::string, std::string> & args,
									       Matrices::SuperMatrixPtr matrix)
		{
			bool useFilteredEntropy = false;
			if (args.find("useFilteredEntropy") != args.end())
				GetBool2(args, "useFilteredEntropy", useFilteredEntropy);
			return weights::WeightFeaturePtr(new weights::LogEntWeight(matrix, useFilteredEntropy));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightLogEntNormalize(std::map<std::string, std::string> & args,
											Matrices::SuperMatrixPtr matrix)
		{
			bool useFilteredEntropy = false;
			if (args.find("useFilteredEntropy") != args.end())
				GetBool2(args, "useFilteredEntropy", useFilteredEntropy);
			return weights::WeightFeaturePtr(new weights::LogEntNormalizeWeight(matrix, useFilteredEntropy));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightMI(std::map<std::string, std::string> & args,
									   Matrices::SuperMatrixPtr matrix)
		{
			double miFilter = 0;
			if (args.find("miFilter") != args.end())
				GetNumber2(args, "miFilter", miFilter);
			return weights::WeightFeaturePtr(new weights::MIWeight(matrix, miFilter));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightMIQuantified(std::map<std::string, std::string> & args,
										     Matrices::SuperMatrixPtr matrix)
		{
			double miFilter = 0;
			int trail = 2;
			bool include_zeros = false;
			if (args.find("miFilter") != args.end())
				GetNumber2(args, "miFilter", miFilter);
			if (args.find("trail") != args.end())
				GetNumber2(args, "trail", trail);
			if (args.find("miFilter") != args.end())
				GetBool2(args, "include_zeros", include_zeros);
			return weights::WeightFeaturePtr(new weights::MIWeightQuantified(matrix, miFilter));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightMLE(std::map<std::string, std::string> & args,
									    Matrices::SuperMatrixPtr matrix)
		{
			return weights::WeightFeaturePtr(new weights::MLEWeightFeature(matrix));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightNormalize(std::map<std::string, std::string> & args,
										  Matrices::SuperMatrixPtr matrix)
		{
			return weights::WeightFeaturePtr(new weights::NormalizeWeight(matrix));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightRFF(std::map<std::string, std::string> & args,
									    Matrices::SuperMatrixPtr matrix)
		{
			if(matrix->GetCCS() == NULL || matrix->GetCRS() == NULL)
			{
				throw std::runtime_error("RFF weigher requires both CCS and CRS matrices loaded. Please adjust your loading options.");
			}
			std::string simmatrix;
			size_t top_k;
			double sim_threshold;
			selectors::RFFSelectorPtr selector;
			if (args.find("simmatrix") != args.end())
				simmatrix = args["simmatrix"];
			else
				throw std::runtime_error("RFF weighter missing required argument: simmatrix");
			if (!boost::filesystem::exists(simmatrix))
			{
				throw std::runtime_error("Invalid argument for RFF weigher: specified similarity matrix does not exist.");
			}

			if (args.find("top_k") != args.end())
				GetNumber2(args, "top_k", top_k);
			else
				throw std::runtime_error("RFF weighter missing required argument: top_k");
			if (args.find("sim_threshold") != args.end())
				GetNumber2(args, "sim_threshold", sim_threshold,0.);
			else
				throw std::runtime_error("RFF weighter missing required argument: sim_threshold");
			if (args.find("selector") != args.end())
			{
				std::string selector_str = args["selector"];
				std::map<std::string,std::string> args_inner;
				std::string namestr, argstr;
				getNameAndArgs(selector_str, namestr, argstr);
				if (namestr != "RFF")
					throw std::runtime_error("RFF weigter requires an RFF selector");
				PrepareArgs(argstr, args_inner, namestr, legal_selector_args[namestr]);
				selector = RFFCreateSelectorRFF(args_inner, matrix);
			}
			else
				throw std::runtime_error("RFF weighter missing required argument: selector");
			return weights::WeightFeaturePtr(new weights::RFFWeight(matrix, simmatrix, top_k, sim_threshold, selector));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightRWF(std::map<std::string, std::string> & args,
									    Matrices::SuperMatrixPtr matrix)
		{
			weights::WeightFeaturePtr weight_inner;
			weights::RankBuilderPtr rankbuilder;
			if (args.find("weight_inner") != args.end())
				weight_inner = CreateWeigher(args["weight_inner"],matrix);
			else
				throw std::runtime_error("RWF weight missing required argument: weight_inner");
			if (args.find("rankbuilder") != args.end())
				rankbuilder = CreateRankBuilder(args["rankbuilder"],matrix);
			else
				throw std::runtime_error("RWF weight missing required argument: rankbuilder");
			return weights::WeightFeaturePtr(new weights::RWFAnyWeight(matrix, rankbuilder, weight_inner));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightRWFChi2(std::map<std::string, std::string> & args,
										Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 0;
			weights::RankBuilderPtr rankbuilder;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			if (args.find("rankbuilder") != args.end())
				rankbuilder = CreateRankBuilder(args["rankbuilder"],matrix);
			else
				throw std::runtime_error("RWF Chi2 weight missing required argument: rankbuilder");
			return weights::WeightFeaturePtr(new weights::RWFChi2(matrix, rankbuilder, threshold));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightRWFEvertsMI(std::map<std::string, std::string> & args,
										    Matrices::SuperMatrixPtr matrix)
		{
			double mi_threshold = 0;
			weights::RankBuilderPtr rankbuilder;
			if (args.find("mi_threshold") != args.end())
				GetNumber2(args, "mi_threshold", mi_threshold);
			if (args.find("rankbuilder") != args.end())
				rankbuilder = CreateRankBuilder(args["rankbuilder"],matrix);
			else
				throw std::runtime_error("RWF Everts MI weight missing required argument: rankbuilder");
			return weights::WeightFeaturePtr(new weights::RWFEvertsMI(matrix, rankbuilder, mi_threshold));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightRWFLin(std::map<std::string, std::string> & args,
									       Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 0;
			weights::RankBuilderPtr rankbuilder;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			if (args.find("rankbuilder") != args.end())
				rankbuilder = CreateRankBuilder(args["rankbuilder"],matrix);
			else
				throw std::runtime_error("RWF lin weight missing required argument: rankbuilder");
			return weights::WeightFeaturePtr(new weights::RWFLinWeight(matrix, rankbuilder, threshold));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightRWFLinFiltered(std::map<std::string, std::string> & args,
										       Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 0;
			weights::RankBuilderPtr rankbuilder;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			if (args.find("rankbuilder") != args.end())
				rankbuilder = CreateRankBuilder(args["rankbuilder"],matrix);
			else
				throw std::runtime_error("RWF lin filtered weight missing required argument: rankbuilder");
			return weights::WeightFeaturePtr(new weights::RWFLinFilteredWeight(matrix, rankbuilder, threshold));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightRWFLogLikelihood(std::map<std::string, std::string> & args,
											 Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 0;
			weights::RankBuilderPtr rankbuilder;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			else
				throw std::runtime_error("RWF log likelihood weight  missing required argument: threshold");
			if (args.find("rankbuilder") != args.end())
				rankbuilder = CreateRankBuilder(args["rankbuilder"],matrix);
			else
				throw std::runtime_error("RWF log likelihood weight missing required argument: rankbuilder");
			return weights::WeightFeaturePtr(new weights::RWFLogLikelihood(matrix, rankbuilder, threshold));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightRWFNoWeight(std::map<std::string, std::string> & args,
										    Matrices::SuperMatrixPtr matrix)
		{
			weights::RankBuilderPtr rankbuilder;
			if (args.find("rankbuilder") != args.end())
				rankbuilder = CreateRankBuilder(args["rankbuilder"],matrix);
			else
				throw std::runtime_error("RWF no weight missing required argument: rankbuilder");
			return weights::WeightFeaturePtr(new weights::RWFNoWeight(matrix, rankbuilder));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightRWFPMI(std::map<std::string, std::string> & args,
									       Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 0;
			bool discount = true;
			weights::RankBuilderPtr rankbuilder;
			if (args.find("discount") != args.end())
				GetBool2(args, "discount", discount);
			if (args.find("discount") != args.end())
				GetNumber2(args, "threshold", threshold);
			if (args.find("rankbuilder") != args.end())
				rankbuilder = CreateRankBuilder(args["rankbuilder"],matrix);
			else
				throw std::runtime_error("RWF log likelihood weight missing required argument: rankbuilder");
			return weights::WeightFeaturePtr(new weights::RWFPMIWeight(matrix, rankbuilder, discount, threshold));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightRWFZScore(std::map<std::string, std::string> & args,
										  Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 2.57;
			weights::RankBuilderPtr rankbuilder;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			if (args.find("rankbuilder") != args.end())
				rankbuilder = CreateRankBuilder(args["rankbuilder"],matrix);
			else
				throw std::runtime_error("RWF Z Score weight missing required argument: rankbuilder");
			return weights::WeightFeaturePtr(new weights::RWFZScore(matrix, rankbuilder, threshold));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightRWFZScoreInMatrix(std::map<std::string, std::string> & args,
											  Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 2.57;
			weights::RankBuilderPtr rankbuilder;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			if (args.find("rankbuilder") != args.end())
				rankbuilder = CreateRankBuilder(args["rankbuilder"],matrix);
			else
				throw std::runtime_error("RWF Z Score in matrix weight missing required argument: rankbuilder");
			return weights::WeightFeaturePtr(new weights::RWFZScoreInMatrixWeight(matrix, rankbuilder, threshold));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightRWFZScoreLocal(std::map<std::string, std::string> & args,
										       Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 2.57;
			weights::RankBuilderPtr rankbuilder;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			if (args.find("rankbuilder") != args.end())
				rankbuilder = CreateRankBuilder(args["rankbuilder"],matrix);
			else
				throw std::runtime_error("RWF Z Score local weight missing required argument: rankbuilder");
			return weights::WeightFeaturePtr(new weights::RWFLocalZScoreWeight(matrix, rankbuilder, threshold));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightSimpleMI(std::map<std::string, std::string> & args,
										 Matrices::SuperMatrixPtr matrix)
		{
			bool discount = true;
			double mi_threshold = 0;
			if (args.find("discount") != args.end())
				GetBool2(args, "discount", discount);
			if (args.find("mi_threshold") != args.end())
				GetNumber2(args, "mi_threshold", mi_threshold);
			return weights::WeightFeaturePtr(new weights::SimpleMIWeight(matrix, discount));
		}
		weights::WeightFeaturePtr FunctionFactory2::CreateWeightPMINoLog(std::map<std::string, std::string> & args,
										 Matrices::SuperMatrixPtr matrix)
		{
			bool discount = true;
			double mi_threshold = 0;
			if (args.find("discount") != args.end())
				GetBool2(args, "discount", discount);
			if (args.find("mi_threshold") != args.end())
				GetNumber2(args, "mi_threshold", mi_threshold);
			return weights::WeightFeaturePtr(new weights::PMINoLog(matrix, discount));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightTfidf(std::map<std::string, std::string> & args,
									      Matrices::SuperMatrixPtr matrix)
		{
			return weights::WeightFeaturePtr(new weights::TfidfWeight(matrix));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightTfidfNormalize(std::map<std::string, std::string> & args,
										       Matrices::SuperMatrixPtr matrix)
		{
			return weights::WeightFeaturePtr(new weights::TfidfNormalizeWeight(matrix));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightTScore(std::map<std::string, std::string> & args,
									       Matrices::SuperMatrixPtr matrix)
		{
			return weights::WeightFeaturePtr(new weights::TScoreWeight(matrix));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightRowScaled(std::map<std::string, std::string> & args,
										  Matrices::SuperMatrixPtr matrix)
		{
			weights::WeightFeaturePtr weight_inner;
			if (args.find("weight_inner") != args.end())
				weight_inner = CreateWeigher(args["weight_inner"],matrix);
			else
				throw std::runtime_error("Row scaled weight missing required argument: weight_inner");
			return weights::WeightFeaturePtr(new weights::RowScaledWeight(matrix, weight_inner));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightColumnScaled(std::map<std::string, std::string> & args,
										     Matrices::SuperMatrixPtr matrix)
		{
			if(matrix->GetCCS() == NULL)
			{
				throw std::runtime_error("Column scaled weighter requires a loaded CCS matrix. Please adjust your loading options.");
			}
			weights::WeightFeaturePtr weight_inner;
			if (args.find("weight_inner") != args.end())
				weight_inner = CreateWeigher(args["weight_inner"],matrix);
			else
				throw std::runtime_error("Column scaled weight missing required argument: weight_inner");
			return weights::WeightFeaturePtr(new weights::ColumnScaledWeight(matrix, weight_inner));
		}
		weights::WeightFeaturePtr FunctionFactory2::CreateWeightBoundaryScaled(std::map<std::string, std::string> & args,
										       Matrices::SuperMatrixPtr matrix)
		{
			weights::WeightFeaturePtr weight_inner;
			double AdjP=0.8, AmISubj=0.6, Coord=0.8, NGen=0.6;
			if (args.find("weight_inner") != args.end())
				weight_inner = CreateWeigher(args["weight_inner"],matrix);
			else
				throw std::runtime_error("Column scaled weight missing required argument: weight_inner");
			if (args.find("AdjP") != args.end())
				GetNumber2(args, "AdjP", AdjP);
			if (args.find("AmISubj") != args.end())
				GetNumber2(args, "AmISubj", AmISubj);
			if (args.find("Coord") != args.end())
				GetNumber2(args, "Coord", Coord);
			if (args.find("NGen") != args.end())
				GetNumber2(args, "NGen", NGen);
			return weights::WeightFeaturePtr(new weights::BoundaryScaledWeight(matrix, weight_inner, AdjP, AmISubj, Coord, NGen));
		}
		weights::WeightFeaturePtr FunctionFactory2::CreateWeightQuantify(std::map<std::string, std::string> & args,
										 Matrices::SuperMatrixPtr matrix)
		{
			bool zeros = false;
			int trailing_digits = 2;
			weights::WeightFeaturePtr weight_inner;
			if (args.find("weight_inner") != args.end())
				weight_inner = CreateWeigher(args["weight_inner"],matrix);
			else
				throw std::runtime_error("Quantify weight missing required argument: weight_inner");
			if (args.find("trailing_digits") != args.end())
				GetNumber2(args, "trailing_digits", trailing_digits);
			if (args.find("zeros") != args.end())
				GetBool2(args, "zeros", zeros);
			return weights::WeightFeaturePtr(new weights::QuantizationWeight(matrix, weight_inner, trailing_digits, zeros));
		}
		weights::WeightFeaturePtr FunctionFactory2::CreateWeightLogLikelihood(std::map<std::string, std::string> & args,
										 Matrices::SuperMatrixPtr matrix)
		{
			double threshold;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			else
				throw std::runtime_error("Log likelihood weight missing required argument: threshold");
			return weights::WeightFeaturePtr(new weights::LogLikelihood(matrix,threshold));
		}
		weights::WeightFeaturePtr FunctionFactory2::CreateWeightZScore(std::map<std::string, std::string> & args,
										 Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 2.57;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			return weights::WeightFeaturePtr(new weights::ZScore(matrix,threshold));
		}
		weights::WeightFeaturePtr FunctionFactory2::CreateWeightZScoreLocal(std::map<std::string, std::string> & args,
										 Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 2.57;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			return weights::WeightFeaturePtr(new weights::LocalZScoreWeight(matrix,threshold));
		}
		weights::WeightFeaturePtr FunctionFactory2::CreateWeightZScoreMatrix(std::map<std::string, std::string> & args,
										 Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 2.57;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			return weights::WeightFeaturePtr(new weights::ZScoreInMatrixWeight(matrix,threshold));
		}
		weights::WeightFeaturePtr FunctionFactory2::CreateWeightChi2(std::map<std::string, std::string> & args,
										 Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 0;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			return weights::WeightFeaturePtr(new weights::Chi2(matrix,threshold));
		}
		weights::WeightFeaturePtr FunctionFactory2::CreateWeightEvertsMI(std::map<std::string, std::string> & args,
										 Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 0;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			return weights::WeightFeaturePtr(new weights::EvertsMI(matrix,threshold));
		}
		weights::WeightFeaturePtr FunctionFactory2::CreateWeightBeta(
				std::map<std::string, std::string>& 	args,
				Matrices::SuperMatrixPtr 				matrix)
		{
			weights::Beta::Params params = {0.0};
			if (args.find("params") != args.end()){
				std::string m = args.find("params")->second;
				std::transform(m.begin(), m.end(), m.begin(), ::tolower);
				if(m == "rr"){
					params = {1.0, 0.0, 0.0, 0.0};
				} else if(m == "pmi"){
					params = {1.0, -1.0, -1.0, 0.0};
				} else if(m == "md"){
					params = {2.0, -1.0, -1.0, 0.0};
				} else if(m == "dk"){
					params = {1.0, -0.5, -0.5, 0.0};
				} else if(m == "fbmd"){
					params = {3.0, -1.0, -1.0, 0.0};
				} else if(m == "fscp"){
					params = {3.0, -1.0, -1.0, 0.0};
				} else if(m == "ne"){
					params = {1.0, 0.0, 0.0, -1.0};
				} else if(m == "ne"){
					params = {1.0, 0.0, 0.0, -1.0};
				} else if(m == "me"){
					params = {2.0, 0.0, 0.0, -1.0};
				} else if(m == "jaccard"){
					params = {1.0, 0.0, 0.0, 1.0};
				} else if(m == "sk"){
					params = {-1.0, 1.0, 1.0, -1.0};
				} else if(m == "sci"){
					params = {1.0, -1.0, -0.5, 0.0};
				} else {
					throw std::runtime_error("unknown parameters pack in beta (params)");
				}
			}

			if (args.find("q") != args.end())
				GetNumber2(args, "q", params.q);
			if (args.find("r") != args.end())
				GetNumber2(args, "r", params.r);
			if (args.find("s") != args.end())
				GetNumber2(args, "s", params.s);
			if (args.find("t") != args.end())
				GetNumber2(args, "t", params.t);

			weights::Beta::ModifierPtrS	modifier;
			if (args.find("modifier") != args.end()){
				std::string m = args.find("modifier")->second;
				std::transform(m.begin(), m.end(), m.begin(), ::tolower);
				if(m == "ln"){
					modifier = weights::Beta::ModifierPtrS(new weights::Beta::ModifierLn());
				} else if(m == "inverse"){
					modifier = weights::Beta::ModifierPtrS(new weights::Beta::ModifierInverse());
				} else if(m.substr(0, 10) == "multiplier"){
					double modValue = atof(m.substr(10).data());
					modifier = weights::Beta::ModifierPtrS(new weights::Beta::ModifierMultiplier(modValue));
				} else {
					throw std::runtime_error("unknown modifier in Beta");
				}
			} else {
				modifier = weights::Beta::ModifierPtrS(new weights::Beta::Modifier());
			}

			return weights::WeightFeaturePtr(new weights::Beta(matrix, params, modifier));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightFirstKulczynsky(
			std::map<std::string, std::string> & args,
			Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 0.0;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			return weights::WeightFeaturePtr(new weights::FirstKulczynsky(matrix,threshold));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightUnigramSubtuples(
			std::map<std::string, std::string> & args,
			Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 0.0;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			return weights::WeightFeaturePtr(new weights::UnigramSubtuples(matrix,threshold));
		}

		weights::WeightFeaturePtr FunctionFactory2::CreateWeightSCost(
			std::map<std::string, std::string> & args,
			Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 0.0;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			return weights::WeightFeaturePtr(new weights::SCost(matrix,threshold));
		}


		weights::RankBuilderPtr FunctionFactory2::CreateRankBuilder(const std::string& rank_str,
									   Matrices::SuperMatrixPtr matrix)
		{
			std::map<std::string,std::string> args;
			std::string namestr, argstr;
			getNameAndArgs(rank_str, namestr, argstr);
			if (rank_functions.find(namestr) == rank_functions.end())
				throw std::runtime_error("Unknown rank builder identifier: " + namestr);
			PrepareArgs(argstr, args, namestr, legal_rank_args[namestr]);
			if (rank_functions.find(namestr) != rank_functions.end())
			{
				return rank_functions[namestr](this, args, matrix);
			}
			throw std::runtime_error("Unknown rank builder identifier: " + namestr);
		}

		weights::RankBuilderPtr FunctionFactory2::CreateRankNormal(std::map<std::string, std::string> & args,
									   Matrices::SuperMatrixPtr matrix)
		{
			bool uniform_rank = false;
			size_t rank_size = 350;
			if (args.find("uniform_rank") != args.end())
				GetBool2(args, "uniform_rank", uniform_rank);
			if (args.find("rank_size") != args.end())
				GetNumber2(args, "rank_size", rank_size);
			return weights::RankBuilderPtr(new weights::NormalRankBuilder(matrix, rank_size, uniform_rank));
		}

		weights::RankBuilderPtr FunctionFactory2::CreateRankPartial(std::map<std::string, std::string> & args,
									    Matrices::SuperMatrixPtr matrix)
		{
			bool uniform_rank = false;
			bool sport_ranking = false;
			bool idf = false;
			size_t rank_size = 350;
			double idf_strength = 1.0;
			if (args.find("uniform_rank") != args.end())
				GetBool2(args, "uniform_rank", uniform_rank);
			if (args.find("sport_ranking") != args.end())
				GetBool2(args, "sport_ranking", sport_ranking);
			if (args.find("idf") != args.end())
				GetBool2(args, "idf", idf);
			if (args.find("rank_size") != args.end())
				GetNumber2(args, "rank_size", rank_size);
			if (args.find("idf_strength") != args.end())
				GetNumber2(args, "idf_strength", idf_strength);

			throw std::runtime_error("The partial order rank builder is an abstract class and cannot be instantiated.");
			return weights::RankBuilderPtr();
			//return weights::RankBuilderPtr(new weights::PartialOrderRankBuilder(matrix, rank_size, uniform_rank, sport_ranking,
			//								idf, idf_strength));
		}

		weights::RankBuilderPtr FunctionFactory2::CreateRankRoundingBasedPartial(std::map<std::string, std::string> & args,
											 Matrices::SuperMatrixPtr matrix)
		{
			bool uniform_rank = false;
			bool sport_ranking = false;
			bool idf = false;
			size_t rank_size = 350;
			double idf_strength = 1.0;
			double divide_factor = 10.0;
			if (args.find("uniform_rank") != args.end())
				GetBool2(args, "uniform_rank", uniform_rank);
			if (args.find("sport_ranking") != args.end())
				GetBool2(args, "sport_ranking", sport_ranking);
			if (args.find("idf") != args.end())
				GetBool2(args, "idf", idf);
			if (args.find("rank_size") != args.end())
				GetNumber2(args, "rank_size", rank_size);
			if (args.find("idf_strength") != args.end())
				GetNumber2(args, "idf_strength", idf_strength);
			if (args.find("divide_factor") != args.end())
				GetNumber2(args, "divide_factor", divide_factor);

			return weights::RankBuilderPtr(new weights::RoundingBasedPartialOrder(matrix, rank_size, uniform_rank, divide_factor, sport_ranking,
											      idf, idf_strength));
		}

		weights::LocalWeightFeaturePtr FunctionFactory2::CreateLocalWeigher(const std::string& weigher_str)
		{
			std::map<std::string,std::string> args;
			std::string namestr, argstr;
			getNameAndArgs(weigher_str, namestr, argstr);
			if (localweight_functions.find(namestr) == localweight_functions.end())
				throw std::runtime_error("Unknown local weigher function identifier: " + namestr);
			PrepareArgs(argstr, args, namestr, legal_localweigher_args[namestr]);
			if (localweight_functions.find(namestr) != localweight_functions.end())
			{
				return localweight_functions[namestr](this, args);
			}
			throw std::runtime_error("Unknown local weigher function identifier: " + namestr);
		}
		weights::LocalWeightFeaturePtr FunctionFactory2::CreateLocalWeightLogEnt(std::map<std::string, std::string> & args)
		{
			bool useFilteredEntropy = false;
			if (args.find("useFilteredEntropy") != args.end())
				GetBool2(args, "useFilteredEntropy", useFilteredEntropy);
			return weights::LocalWeightFeaturePtr(new weights::LocalLogEntWeight(useFilteredEntropy));
		}

		transformations::TransformationPtr FunctionFactory2::CreateTransformation(const std::string& transformation_str,
											  Matrices::SuperMatrixPtr matrix)
		{
			std::map<std::string, std::string> args;
			std::string namestr, argstr;
			getNameAndArgs(transformation_str, namestr, argstr);

			if (transformation_functions.find(namestr)== transformation_functions.end())
				throw std::runtime_error("Unknown transformation identifier: " + namestr);
			PrepareArgs(argstr, args, namestr, legal_transformation_args[namestr]);
			if (transformation_functions.find(namestr) != transformation_functions.end())
			{
				return transformation_functions[namestr](this, args, matrix);
			}
			throw std::runtime_error("Unknown transformation identifier: " + namestr);
		}
		transformations::TransformationPtr FunctionFactory2::CreateTransformationSVD(std::map<std::string, std::string> & args,
											     Matrices::SuperMatrixPtr matrix)
		{
			size_t dim=0;
			if (args.find("dimensions") != args.end())
				GetNumber2(args, "dimensions", dim);
			return transformations::TransformationPtr(new transformations::SVDTransformation(matrix, dim));
		}
		transformations::TransformationPtr FunctionFactory2::CreateTransformationLDA(std::map<std::string, std::string> & args,
											     Matrices::SuperMatrixPtr matrix)
		{
			size_t num_topics=0;
			size_t passes=10;
			std::string temp_dir;
			if (args.find("num_topics") != args.end())
				GetNumber2(args, "num_topics", num_topics);
			else
				throw std::runtime_error("Transformation LDA missing required argument: num_topics");
			if (args.find("passes") != args.end())
				GetNumber2(args, "passes", passes);
			if (args.find("temp_dir") != args.end())
				GetStr2(args, "temp_dir", temp_dir);

			return transformations::TransformationPtr(new transformations::LDATransformation(matrix, num_topics, passes, temp_dir));
		}

		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunction(const std::string& simfunction_str,
											Matrices::SuperMatrixPtr matrix)
		{
			std::map<std::string,std::string> args;
			std::string namestr, argstr;
			getNameAndArgs(simfunction_str, namestr, argstr);
			if (simfunctions_functions.find(namestr) == simfunctions_functions.end())
				throw std::runtime_error("Unknown similarity function identifier: " + namestr);
			PrepareArgs(argstr, args, namestr, legal_simfunction_args[namestr]);
			if (simfunctions_functions.find(namestr) != simfunctions_functions.end())
			{
				return simfunctions_functions[namestr](this, args, matrix);
			}
			throw std::runtime_error("Unknown similarity function identifier: " + namestr);
		}

		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionCosine(std::map<std::string, std::string> & args,
											      Matrices::SuperMatrixPtr matrix)
		{
			bool matrixNormalized = false;
			if (args.find("matrixNormalized") != args.end())
				GetBool2(args, "matrixNormalized", matrixNormalized);
			return simfunctions::SimilarityFunctionPtr(new simfunctions::CosineFunction(matrix, matrixNormalized));
		}

		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionCosineFilter(std::map<std::string, std::string> & args,
												    Matrices::SuperMatrixPtr matrix)
		{
			double percentInter = 0.1;
			size_t minInter = 2;
			if (args.find("percentInter") != args.end())
				GetNumber2(args, "percentInter", percentInter);
			if (args.find("minInter") != args.end())
				GetNumber2(args, "minInter", minInter);
			return simfunctions::SimilarityFunctionPtr(new simfunctions::CosineFilterSimilarity(matrix, percentInter, minInter));
		}

		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionCRM(std::map<std::string, std::string> & args,
											   Matrices::SuperMatrixPtr matrix)
		{
			double gamma = 0.25;
			double beta = 0.2;
			if (args.find("gamma") != args.end())
				GetNumber2(args, "gamma", gamma);
			if (args.find("beta") != args.end())
				GetNumber2(args, "beta", beta);
			return simfunctions::SimilarityFunctionPtr(new simfunctions::SimCRM(matrix, gamma, beta));
		}

		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionDice(std::map<std::string, std::string> & args,
											    Matrices::SuperMatrixPtr matrix)
		{
			return simfunctions::SimilarityFunctionPtr(new simfunctions::Dice(matrix));
		}
		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionDiceBugged(std::map<std::string, std::string> & args,
											    Matrices::SuperMatrixPtr matrix)
		{
			double power = 1;
			bool normalize = true;
			if (args.find("power") != args.end())
				GetNumber2(args, "power", power);
			if (args.find("normalize") != args.end())
				GetBool2(args, "normalize", normalize);
			return simfunctions::SimilarityFunctionPtr(new simfunctions::DiceBugged(matrix,power,normalize));
		}

		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionEhlert(std::map<std::string, std::string> & args,
											      Matrices::SuperMatrixPtr matrix)
		{
			double delta = 0.75;
			double gamma = 0.75;
			double alpha = 1.1;
			if (args.find("delta") != args.end())
				GetNumber2(args, "delta", delta);
			if (args.find("gamma") != args.end())
				GetNumber2(args, "gamma", gamma);
			if (args.find("alpha") != args.end())
				GetNumber2(args, "alpha", alpha);
			throw std::runtime_error("Ehlert similarity function class is incomplete at this time.");
			//return simfunctions::SimilarityFunctionPtr(new simfunctions::EhlertSimilarity(matrix, delta, gamma, alpha));
		}

		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionFile(std::map<std::string, std::string> & args,
											    Matrices::SuperMatrixPtr matrix)
		{
			std::string sim_matrix;
			if (args.find("sim_matrix") != args.end())
				sim_matrix = args["sim_matrix"];
			return simfunctions::SimilarityFunctionPtr(new simfunctions::FileSimFunction(matrix, sim_matrix));
		}

		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionJaccard(std::map<std::string, std::string> & args,
											       Matrices::SuperMatrixPtr matrix)
		{
			return simfunctions::SimilarityFunctionPtr(new simfunctions::Jaccard(matrix));
		}

		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionLin(std::map<std::string, std::string> & args,
											   Matrices::SuperMatrixPtr matrix)
		{
			return simfunctions::SimilarityFunctionPtr(new simfunctions::LinSimilarity(matrix));
		}

		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionMCF(std::map<std::string, std::string> & args,
											   Matrices::SuperMatrixPtr matrix)
		{
			double threshold = 0.14;
			weights::WeightFeaturePtr weight;
			simfunctions::SimilarityFunctionPtr sim_inner;
			if (args.find("threshold") != args.end())
				GetNumber2(args, "threshold", threshold);
			if (args.find("sim_inner") != args.end())
				sim_inner = CreateSimfunction(args["sim_inner"], matrix);
			else
				throw std::runtime_error("MCF similarity missing required argument: sim_inner");
			if (args.find("weight") != args.end())
				weight = CreateWeigher(args["weight"], matrix);
			else
				throw std::runtime_error("MCF similarity missing required argument: weight");
			return simfunctions::SimilarityFunctionPtr(new simfunctions::MCFSim(matrix, sim_inner, weight, threshold));
		}
		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionPEntP(std::map<std::string, std::string> & args,
											     Matrices::SuperMatrixPtr matrix)
		{
			return simfunctions::SimilarityFunctionPtr(new simfunctions::PEntP(matrix));
		}

		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionSHD(std::map<std::string, std::string> & args,
											   Matrices::SuperMatrixPtr matrix)
		{
			double alpha = 0.5;
			if (args.find("alpha") != args.end())
				GetNumber2(args, "alpha", alpha);
			return simfunctions::SimilarityFunctionPtr(new simfunctions::SHD(matrix, alpha));
		}
		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionDistance(std::map<std::string, std::string> & args,
												Matrices::SuperMatrixPtr matrix)
		{
			distances::DistanceFunctionPtr dist;
			if (args.find("dist") != args.end())
			{
				dist = CreateDistfunction(args["dist"], matrix);
			}
			else
			{
				throw std::runtime_error("Dinstance similarity missing required argument: dist");
			}
			return simfunctions::SimilarityFunctionPtr(new simfunctions::DistanceSim(matrix, dist));
		}
		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionRatio(std::map<std::string, std::string> & args,
											     Matrices::SuperMatrixPtr matrix)
		{
			return simfunctions::SimilarityFunctionPtr(new simfunctions::RatioSim(matrix));
		}
		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionIntersectionScaled(std::map<std::string, std::string> & args,
											     Matrices::SuperMatrixPtr matrix)
		{
			simfunctions::SimilarityFunctionPtr sim_inner;
			bool countVals = true;
			if (args.find("countVals") != args.end())
			{
				GetBool2(args, "countVals", countVals);
			}
			if (args.find("sim_inner") != args.end())
			{
				sim_inner = CreateSimfunction(args["sim_inner"], matrix);
			}
			else
			{
				throw std::runtime_error("Intersection scaled similarity missing required argument: sim_inner");
			}
			return simfunctions::SimilarityFunctionPtr(new simfunctions::IntersectionScaledSimilarity(matrix, sim_inner, countVals));
		}
		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionPartialMSR(std::map<std::string, std::string> & args,
												   Matrices::SuperMatrixPtr matrix)
		{
			if( args.find("sim_inner") == args.end() )
				throw std::runtime_error("PartialMSR missing required argument: sim_inner");
			if( args.find("freq_supermatrix_dir") == args.end() )
				throw std::runtime_error("PartialMSR missing required argument: freq_supermatrix_dir");
			if( args.find("freq_supermatrix_name") == args.end() )
				throw std::runtime_error("PartialMSR missing required argument: freq_supermatrix_name");

			simfunctions::SimilarityFunctionPtr simFunction =
					CreateSimfunction( args["sim_inner"], matrix );

			Matrices::SuperMatrixPtr freq = simfunctions::PartialMSR::LoadFrequencies(
					args["freq_supermatrix_dir"], args["freq_supermatrix_name"] );

			simfunctions::PartialMSR::IndicesPtr badFeatures =
					args.find("bad_features_file") != args.end() ?
							simfunctions::PartialMSR::ReadBadFeatures( args["bad_features_file"] ) :
							simfunctions::PartialMSR::IndicesPtr( new simfunctions::PartialMSR::Indices() );

			return simfunctions::SimilarityFunctionPtr(
					new simfunctions::PartialMSR( matrix, freq, badFeatures, simFunction ) );
		}
		void FunctionFactory2::verifyParamsForPartialMSR2( std::map<std::string, std::string> const& pParams )
		{
			// data
			if( pParams.find("freq_supermatrix_dir") == pParams.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: freq_supermatrix_dir");
			if( pParams.find("freq_supermatrix_name") == pParams.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: freq_supermatrix_name");

			// DB
			if( pParams.find("db_host") == pParams.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: db_host");
			if( pParams.find("db_port") == pParams.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: db_port");
			if( pParams.find("db_name") == pParams.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: db_name");
			if( pParams.find("db_user") == pParams.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: db_user");
			if( pParams.find("db_pass") == pParams.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: db_pass");
			if( pParams.find("db_language") == pParams.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: db_language, valid: pl, eng");

			// params
			if( pParams.find("param_features_percent_to_remove") == pParams.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: param_features_percent_to_remove");
			if( pParams.find("param_sim_inner") == pParams.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: param_sim_inner");
			if( pParams.find("param_weight_inner") == pParams.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: param_weight_inner");
			if( pParams.find("param_min_tree_equality") == pParams.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: param_min_tree_equality");
			if( pParams.find("param_classes") == pParams.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: param_classes");
			if( pParams.find("param_min_feature_weight_for_lemma") == pParams.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: param_min_feature_weight_for_lemma");
		}
		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionPartialMSR2A(
			std::map<std::string, std::string>& args,
			Matrices::SuperMatrixPtr 			matrix )
		{
			verifyParamsForPartialMSR2( args );

			if( args.find("param_k") == args.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: param_k");

			simfunctions::SimilarityFunctionPtr simFunction = CreateSimfunction( args["param_sim_inner"], matrix );

			simfunctions::DBManagerMySQL::ConnectionInfo cinfo;
			cinfo.dbname 	= args["db_name"];
			cinfo.hostaddr 	= args["db_host"];
			cinfo.password 	= args["db_pass"];
			cinfo.port 		= boost::lexical_cast<unsigned int>( args["db_port"] );
			cinfo.user 		= args["db_user"];
			cinfo.language	=
				args["db_language"] == "eng" ? simfunctions::DBManagerMySQL::ENGLISH :
				args["db_language"] == "pl" ? simfunctions::DBManagerMySQL::POLISH :
				simfunctions::DBManagerMySQL::POLISH;

			simfunctions::PartialMSR2A::Params params;
			params.featuresPercentToRemove 	= boost::lexical_cast<double>( args["param_features_percent_to_remove"] );
			params.minTreesCutEquality 		= boost::lexical_cast<double>( args["param_min_tree_equality"] );
			params.minFeatureWeightForLemma	= boost::lexical_cast<double>( args["param_min_feature_weight_for_lemma"] );
			params.numberOfClasses 			= boost::lexical_cast<size_t>( args["param_classes"] );
			params.weightCmpFunction 		= args["param_weight_inner"];

			simfunctions::PartialMSR2A::ParamsA paramsA;
			paramsA.k = boost::lexical_cast<unsigned int>( args["param_k"] );

			simfunctions::DBManagerMySQL dbmgr;
			if( !dbmgr.connect( cinfo ) )
				throw std::runtime_error("PartialMSR2: cannot connect to db");

			simfunctions::SynsetClassSetPtrS synsetClassSet = dbmgr.loadSynsetClassesFromMySQL();

			Matrices::SuperMatrixPtr freq = simfunctions::PartialMSR2Base::LoadFrequencies(
					args["freq_supermatrix_dir"], args["freq_supermatrix_name"] );

			simfunctions::PartialMSR2APtrS partialmsr2(
					new simfunctions::PartialMSR2A( matrix, simFunction, synsetClassSet, params, paramsA ) );
			partialmsr2->init( freq );

			return partialmsr2;
		}
		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionPartialMSR2B(
			std::map<std::string, std::string>& args,
			Matrices::SuperMatrixPtr 			matrix )
		{
			verifyParamsForPartialMSR2( args );

			if( args.find("param_n") == args.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: param_n");
			if( args.find("param_k") == args.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: param_k");

			simfunctions::SimilarityFunctionPtr simFunction = CreateSimfunction( args["param_sim_inner"], matrix );

			simfunctions::DBManagerMySQL::ConnectionInfo cinfo;
			cinfo.dbname 	= args["db_name"];
			cinfo.hostaddr 	= args["db_host"];
			cinfo.password 	= args["db_pass"];
			cinfo.port 		= boost::lexical_cast<unsigned int>( args["db_port"] );
			cinfo.user 		= args["db_user"];
			cinfo.language	=
				args["db_language"] == "eng" ? simfunctions::DBManagerMySQL::ENGLISH :
				args["db_language"] == "pl" ? simfunctions::DBManagerMySQL::POLISH :
				simfunctions::DBManagerMySQL::POLISH;

			simfunctions::PartialMSR2B::Params params;
			params.featuresPercentToRemove 	= boost::lexical_cast<double>( args["param_features_percent_to_remove"] );
			params.minTreesCutEquality 		= boost::lexical_cast<double>( args["param_min_tree_equality"] );
			params.minFeatureWeightForLemma	= boost::lexical_cast<double>( args["param_min_feature_weight_for_lemma"] );
			params.numberOfClasses 			= boost::lexical_cast<size_t>( args["param_classes"] );
			params.weightCmpFunction 		= args["param_weight_inner"];

			simfunctions::PartialMSR2B::ParamsB paramsB;
			paramsB.k = boost::lexical_cast<unsigned int>( args["param_k"] );
			paramsB.n = boost::lexical_cast<unsigned int>( args["param_n"] );

			simfunctions::DBManagerMySQL dbmgr;
			if( !dbmgr.connect( cinfo ) )
				throw std::runtime_error("PartialMSR2: cannot connect to db");

			simfunctions::SynsetClassSetPtrS synsetClassSet = dbmgr.loadSynsetClassesFromMySQL();

			Matrices::SuperMatrixPtr freq = simfunctions::PartialMSR2Base::LoadFrequencies(
					args["freq_supermatrix_dir"], args["freq_supermatrix_name"] );

			simfunctions::PartialMSR2BPtrS partialmsr2(
					new simfunctions::PartialMSR2B( matrix, simFunction, synsetClassSet, params, paramsB ) );
			partialmsr2->init( freq );

			return partialmsr2;
		}
		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionPartialMSR2Bp(
			std::map<std::string, std::string>& args,
			Matrices::SuperMatrixPtr 			matrix )
		{
			verifyParamsForPartialMSR2( args );

			if( args.find("param_n") == args.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: param_n");
			if( args.find("param_k") == args.end() )
				throw std::runtime_error("PartialMSR2 missing required argument: param_k");

			simfunctions::SimilarityFunctionPtr simFunction = CreateSimfunction( args["param_sim_inner"], matrix );

			simfunctions::DBManagerMySQL::ConnectionInfo cinfo;
			cinfo.dbname 	= args["db_name"];
			cinfo.hostaddr 	= args["db_host"];
			cinfo.password 	= args["db_pass"];
			cinfo.port 		= boost::lexical_cast<unsigned int>( args["db_port"] );
			cinfo.user 		= args["db_user"];
			cinfo.language	=
				args["db_language"] == "eng" ? simfunctions::DBManagerMySQL::ENGLISH :
				args["db_language"] == "pl" ? simfunctions::DBManagerMySQL::POLISH :
				simfunctions::DBManagerMySQL::POLISH;

			simfunctions::PartialMSR2Bp::Params params;
			params.featuresPercentToRemove 	= boost::lexical_cast<double>( args["param_features_percent_to_remove"] );
			params.minTreesCutEquality 		= boost::lexical_cast<double>( args["param_min_tree_equality"] );
			params.minFeatureWeightForLemma	= boost::lexical_cast<double>( args["param_min_feature_weight_for_lemma"] );
			params.numberOfClasses 			= boost::lexical_cast<size_t>( args["param_classes"] );
			params.weightCmpFunction 		= args["param_weight_inner"];

			simfunctions::PartialMSR2Bp::ParamsBp paramsBp;
			paramsBp.k = boost::lexical_cast<unsigned int>( args["param_k"] );
			paramsBp.n = boost::lexical_cast<unsigned int>( args["param_n"] );

			simfunctions::DBManagerMySQL dbmgr;
			if( !dbmgr.connect( cinfo ) )
				throw std::runtime_error("PartialMSR2: cannot connect to db");

			simfunctions::SynsetClassSetPtrS synsetClassSet = dbmgr.loadSynsetClassesFromMySQL();

			Matrices::SuperMatrixPtr freq = simfunctions::PartialMSR2Base::LoadFrequencies(
					args["freq_supermatrix_dir"], args["freq_supermatrix_name"] );

			simfunctions::PartialMSR2BpPtrS partialmsr2(
					new simfunctions::PartialMSR2Bp( matrix, simFunction, synsetClassSet, params, paramsBp ) );
			partialmsr2->init( freq );

			return partialmsr2;
		}

		simfunctions::SimilarityFunctionPtr FunctionFactory2::CreateSimfunctionBhattacharyya(
			std::map<std::string, std::string>& args,
			Matrices::SuperMatrixPtr 			matrix)
		{
			bool matrixNormalized = false;
			if (args.find("matrixNormalized") != args.end())
				GetBool2(args, "matrixNormalized", matrixNormalized);
			return simfunctions::SimilarityFunctionPtr(new simfunctions::Bhattacharyya(matrix, matrixNormalized));
		}


		simfunctions::LocalSimilarityFunctionPtr FunctionFactory2::CreateLocalSimfunction(const std::string& simfunction_str)
		{
			std::map<std::string,std::string> args;
			std::string namestr, argstr;
			getNameAndArgs(simfunction_str, namestr, argstr);
			if (localsimfunctions_functions.find(namestr) == localsimfunctions_functions.end())
				throw std::runtime_error("Unknown local similarity function identifier: " + namestr);
			PrepareArgs(argstr, args, namestr, legal_localsimfunction_args[namestr]);
			if (localsimfunctions_functions.find(namestr) != localsimfunctions_functions.end())
				return localsimfunctions_functions[namestr](this, args);
			throw std::runtime_error("Unknown local similarity function identifier: " + namestr);
		}

		simfunctions::LocalSimilarityFunctionPtr FunctionFactory2::CreateLocalSimfunctionLocalCosine(std::map<std::string, std::string> & args)
		{
			bool isNormalized;
			bool doFilter;
			double percentInter = 0.1;
			size_t minInter = 2;
			if (args.find("isNormalized") != args.end())
				GetBool2(args, "isNormalized", isNormalized);
			else
				throw std::runtime_error("Local cosine similarity missing required argument: isNormalized");
			if (args.find("doFilter") != args.end())
				GetBool2(args, "doFilter", doFilter);
			else
				throw std::runtime_error("Local cosine similarity missing required argument: doIter");
			if (args.find("percentInter") != args.end())
				GetNumber2(args, "percentInter", percentInter);
			if (args.find("minInter") != args.end())
				GetNumber2(args, "minInter", minInter);
			return simfunctions::LocalSimilarityFunctionPtr(new simfunctions::LocalCosineSimilarity(isNormalized, doFilter,
														percentInter, minInter) );
		}

		simfunctions::LocalSimilarityFunctionPtr FunctionFactory2::CreateLocalSimfunctionIRad(std::map<std::string, std::string> & args)
		{
			weights::LocalWeightFeaturePtr weight;
			double beta = 20;
			if (args.find("weight") != args.end())
				weight = CreateLocalWeigher(args["weight"]);
			if (args.find("beta") != args.end())
				GetNumber2(args, "beta", beta);
			return simfunctions::LocalSimilarityFunctionPtr(new simfunctions::LocalIRad(weight.get(), beta));
		}

		distances::DistanceFunctionPtr FunctionFactory2::CreateDistfunction(const std::string& distfunction_str,
										    Matrices::SuperMatrixPtr matrix)
		{
			std::map<std::string,std::string> args;
			std::string namestr, argstr;
			getNameAndArgs(distfunction_str, namestr, argstr);
			if (distfunctions_functions.find(namestr) == distfunctions_functions.end())
				throw std::runtime_error("Unknown distance function identifier: " + namestr);
			PrepareArgs(argstr, args, namestr, legal_distfunction_args[namestr]);
			if (distfunctions_functions.find(namestr) != distfunctions_functions.end())
			{
				return distfunctions_functions[namestr](this, args, matrix);
			}
			throw std::runtime_error("Unknown distance function identifier: " + namestr);
		}

		distances::DistanceFunctionPtr FunctionFactory2::CreateDistfunctionEuclid(std::map<std::string, std::string> & args,
											  Matrices::SuperMatrixPtr matrix)
		{
			return distances::DistanceFunctionPtr(new distances::EuclidianDist(matrix));
		}
		distances::DistanceFunctionPtr FunctionFactory2::CreateDistfunctionMinkowski(std::map<std::string, std::string> & args,
											     Matrices::SuperMatrixPtr matrix)
		{
			double p = 2;
			if (args.find("p") != args.end())
				GetNumber2(args, "p", p);
			return distances::DistanceFunctionPtr(new distances::MinkowskiDist(matrix, p));
		}

		CompareFunctionPtr FunctionFactory2::CreateComparator(const std::string& comparator_str_const,
								      Matrices::SuperMatrixPtr matrix)
		{
			LOG4CXX_INFO(logger,"Creating comparator for "<<comparator_str_const);
			std::string comparator_str = comparator_str_const;
			boost::erase_all(comparator_str," ");
			weights::WeightFeaturePtr weight;
			selectors::SelectorPtr selector;
			selectors::RowRelativeSelectorPtr relative_selector;
			simfunctions::SimilarityFunctionPtr simfunction;
			filters::FilterFeaturePtr filter;
			transformations::TransformationPtr transformation;

			std::map<std::string,std::string> args;
			std::string namestr, argstr;
			getNameAndArgs(comparator_str, namestr, argstr);
			if (namestr == "ens")
			{
				return FunctionFactory2::CreateComparatorEnsemble(comparator_str_const, matrix);
			}
			if (namestr!="cmp" && namestr!="domain_comparator")
				throw std::runtime_error("Comparator in cmp(<args>) format expected.");


			if (namestr == "domain_comparator")
			{
				std::vector<std::string> legal_domain_args;
				legal_domain_args.push_back("compare_function");
				legal_domain_args.push_back("domain_file");
				legal_domain_args.push_back("label_file");

				PrepareArgs(argstr, args, namestr, legal_domain_args);
				return CreateDomainComparator(args,matrix);
			}

			PrepareArgs(argstr, args, namestr, legal_comparator_args);
			if (args.find("weight") != args.end())
				weight = CreateWeigher(args["weight"], matrix);
			if (args.find("selector") != args.end())
				selector = CreateSelector(args["selector"], matrix);
			if (args.find("relative_selector") != args.end())
				relative_selector = CreateRowRelativeSelector(args["relative_selector"], matrix);
			if (args.find("simfunction") != args.end())
				simfunction = CreateSimfunction(args["simfunction"], matrix);
			if (args.find("filter") != args.end())
				filter = CreateFilter(args["filter"], matrix);
			if (args.find("transformation") !=args.end())
				transformation = CreateTransformation(args["transformation"], matrix);

			CompareFunctionPtr ret = CompareFunctionPtr(new CompareFunction(matrix, filter, selector, weight, simfunction, relative_selector, transformation));
			return ret;
		}

		CompareFunctionPtr FunctionFactory2::CreateComparatorEnsemble(const std::string &comparator_str_const, Matrices::SuperMatrixPtr matrix)
		{
			std::string comparator_str = comparator_str_const;
			std::map<std::string,std::string> args;
			std::string namestr, argstr;
			getNameAndArgs(comparator_str, namestr, argstr);
			if (namestr != "ens")
			{
				throw std::runtime_error("A non-ensemble string called an ensemble constructor? this isn't rigt...");
			}


			std::vector<CompareFunctionPtr> comparators;
			std::vector<double> cmp_weights;
		
			PrepareArgs(argstr, args, namestr, legal_ensemble_args);

			if (args.find("comparator") != args.end())
				comparators.push_back(FunctionFactory2::CreateComparator(args["comparator"], matrix));
			else
				throw std::runtime_error("Comparator ensemble must not be empty (missing required comparator argument)");
			if (args.find("cmp_weight") != args.end())
				cmp_weights.push_back(boost::lexical_cast<double>(args["cmp_weight"]));
			else
				throw std::runtime_error("Comparator ensemble must not be empty (missing required comparator argument)");
			size_t i = 1;
			std::string argname = "comparator1";
			while(args.find(argname) != args.end())
			{
				comparators.push_back(FunctionFactory2::CreateComparator(args[argname], matrix));
				i++;
				argname="comparator"+boost::lexical_cast<std::string>(i);
			}
			i = 1;
			argname = "cmp_weight1";
			while(args.find(argname) != args.end())
			{
				cmp_weights.push_back(boost::lexical_cast<double>(args[argname]));
				i++;
				argname="cmp_weight"+boost::lexical_cast<std::string>(i);
			}

			CompareFunctionPtr ret = CompareFunctionPtr(new EnsembleCompareFunction(comparators, cmp_weights));
			return ret;


		}

		CompareFunctionPtr FunctionFactory2::CreateDomainComparator(std::map<std::string, std::string> & args,
									    Matrices::SuperMatrixPtr matrix)
		{
			std::string compare_function, domain_file, label_file;
			if (args.find("compare_function") != args.end())
				compare_function = args["compare_function"];
			else throw std::runtime_error("Missing a compare function");
			if (args.find("domain_file") != args.end())
				domain_file = args["domain_file"];
			else throw std::runtime_error("Missing a domain_file");
			if(args.find("label_file") != args.end())
				label_file = args["label_file"];
			else throw std::runtime_error("Missing a label_file");

			CompareFunctionPtr ret = CompareFunctionPtr(new DomainComparator(matrix,domain_file, label_file,compare_function));
			return ret;
		}

		void FunctionFactory2::getNameAndArgs(const std::string& str, std::string& name, std::string& args)
		{
			std::string cpy = str;
			boost::trim(cpy);
			std::vector<std::string> arg_tokens;

			boost::regex function_pattern("(\\S+?)\\((\\S*)\\)");

			boost::smatch match;

			if(boost::regex_match(cpy, match, function_pattern) && match.size()==3)
			{
				name = match[1];
				args = match[2];
			}

		}

		void FunctionFactory2::PrepareArgsOld(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
		void FunctionFactory2::PrepareArgs(const std::string &args, std::map<std::string, std::string> & name2val,
						   std::string & identifier, std::vector<std::string> & legal_args)
		{
			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(",") );
				std::vector<std::string> tmp_vector;
				std::string tmp_string="";
				for(size_t i=0; i<arg_tokens.size(); i++)
				{
					if (tmp_string != "")
						tmp_string = tmp_string + "," + arg_tokens[i];
					else
						tmp_string = tmp_string + arg_tokens[i];
					if (std::count(tmp_string.begin(), tmp_string.end(),'(') ==
					    std::count(tmp_string.begin(), tmp_string.end(),')'))
					{
						tmp_vector.push_back(tmp_string);
						tmp_string = "";
					}
					else
					{
					}
				}
				if (tmp_string != "")
				{
					throw std::runtime_error("Unable to parse arguments for string (probably a missing '(' or ')' - unparsed substring: " + tmp_string);
				}
				arg_tokens = tmp_vector;
				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("=") );
						for (size_t k = 2; k < vName2val.size(); k++)
						{
							vName2val[1]+="=";
							vName2val[1]+=vName2val[k];
						}
						//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);
						bool legal = false;
						unsigned int j=0;
						while (j<legal_args.size() && !legal)
						{
							if(legal_args[j] == name)
								legal=true;
							j++;
						}
						if (!legal)
							throw std::runtime_error(name + " is not a valid argument for " + identifier);
						if(name.length() == 0 || value.length() == 0)
							throw std::runtime_error("Wrong format of argumets " + args + ", wrong entry: " + arg_tokens[i] );
						size_t name_id = 1;
						std::string namecore = name;
						while(name2val.find(name) != name2val.end())
						{
							name = namecore + boost::lexical_cast<std::string>(name_id);
							name_id++;
						}
						name2val[name] = value;
					}//if arg_tokens[i].length != 0
				}// for each argument
			}//if copy.lengt > 0
		}//PrepareArgs

	}//compare

}//smartcomparator

