/*********************************************************************
 * This file is part of the PRAPI library.
 *
 * Copyright (C) 2001 Topi Mäenpää
 * All rights reserved.
 *
 * This program is free software. You can redistribute and/or modify
 * it under the terms of the free software licence found in the
 * accompanying file "COPYING". The licence terms must always be
 * redistributed with this source file. The above copyright notice
 * must be reproduced in all modified and unmodified copies of this
 * source file.
 *
 * $Revision: 1.4 $
 *********************************************************************/

#ifndef _FEATURESCALING_H
#define _FEATURESCALING_H

#include "Sample.h"

namespace prapi
{
	/**
	 * This class contains static methods for scaling feature values.
	 * Standard template library (stl) functionals are used as template
	 * parameters to perform the scaling calculations. An example:<br>
	 * <pre>
	 * #include <functional>
	 *
	 * ...
	 *
	 * List&lt;Sample&lt;double&gt; &gt; samples; //produce these somehow
	 * List&lt;double&gt; means, variances;
	 *
	 * //Loop through all features
	 * for (int i=0;i&lt;featureCount;i++)
	 *   {
	 *     //Collect the ith features
	 *     List&lt;double&gt; tmpLst(FeatureScaling::getFeature(samples,i));
	 *
	 *     //Calculate mean and variance
	 *     means += Math::mean(tmpLst);
	 *     variances += Math::variance(tmpList);
	 *   }
	 *
	 *  //Subtract the mean value from each feature.
	 *  FeatureScaling::scaleFeatures&lt;minus&lt;double&gt; &gt;(samples,means);
	 *  //Divide by variance.
	 *  FeatureScaling::scaleFeatures&lt;divides&lt;double&gt; &gt;(samples,variances);
	 * </pre>
	 **/
	class FeatureScaling
	{
	public:
		/**
		 * Get the <i>nth</i> feature from each sample in a sample list.
		 * This method goes through all samples in a list and stores the
		 * <i>nth</i> sample into the resulting list.
		 *
		 * @param samples a list of samples
		 * @param n a zero-based feature index
		 **/
		template <class T, class I, class C> static List<T> getFeature(const List<Sample<T,I,C> >& samples, int n);
		/**
		 * Get the <i>nth</i> feature from the given feature vector of
		 * each sample in a sample list. This method goes through all
		 * samples in a list and stores the <i>nth</i> sample of the
		 * required feature vector into the resulting list.
		 *
		 * @param samples a list of multi-feature samples
		 * @param featureVector a zero-based index to the wanted feature vector
		 * @param n a zero-based feature index
		 **/
		template <class T, class I, class C> static List<T> getFeature(const List<Sample<List<T>,I,C> >& samples,
																																	 int featureVector, int n);

		/*
		 * Multiply feature values by the corresponding values in a list.
		 *
		 * @param samples the samples whose feature vectors are to be
		 * modified
		 * @param values the values to multiply the feature values by
		 **/
		template <class operation, class T, class I, class C>
		static void scaleFeatures(List<Sample<T,I,C> >& samples,
															const List<T>& values);
		/**
		 * Scale feature values with the corresponding values in a list.
		 *
		 * @param samples the samples whose feature vectors are to be
		 * modified
		 * @param featureVector the index of the feature vector to modify
		 * @param values the values to multiply the feature values by
		 **/
		template <class operation, class T, class I, class C>
		static void scaleFeatures(List<Sample<List<T>,I,C> >& samples,
															int featureVector,
															const List<T>& values);
	};

	template <class T, class I, class C> List<T> FeatureScaling::getFeature(const List<Sample<T,I,C> >& samples, int n)
	{
		List<T> result(samples.getLength());
		for (int i=0;i<samples.getLength();i++)
			result += samples[i].featureVector()[n];
		return result;
	}

	template <class T, class I, class C> List<T> FeatureScaling::getFeature(const List<Sample<List<T>,I,C> >& samples,
																																					int featureVector, int n)
	{
		List<T> result(samples.getLength());
		for (int i=0;i<samples.getLength();i++)
			result += samples[i].featureVector()[featureVector][n];
		return result;
	}

	template <class operation, class T, class I, class C>
	void FeatureScaling::scaleFeatures(List<Sample<T,I,C> >& samples,
																		 const List<T>& values)
	{
		operation o;
		int len = values.getLength();
		for (int i=0;i<samples.getLength();i++)
			{
				List<T> &features = samples[i].featureVector();
				int minLength = len <= features.getLength() ? len : features.getLength();
				for (int j=0;j<minLength;j++)
					features[j] = o(features[j],values[j]);
			}
	}
	

	template <class operation, class T, class I, class C>
	void FeatureScaling::scaleFeatures(List<Sample<List<T>,I,C> >& samples,
																		 int featureVector,
																		 const List<T>& values)
	{
		operation o;
		int len = values.getLength();
		for (int i=0;i<samples.getLength();i++)
			{
				List<T> &features = samples[i].featureVector()[featureVector];
				int minLength = len <= features.getLength() ? len : features.getLength();
				for (int j=0;j<minLength;j++)
					features[j] = o(features[j],values[j]);
			}
	}
}

#endif
