/*
 * Selection.h
 *
 *  Created on: Jul 27, 2015
 *      Author: jjpalacios
 */

#ifndef SRC_ECOPERATORS_SELECTION_H_
#define SRC_ECOPERATORS_SELECTION_H_


#include "../heading.h"
#include "../ecObjects/SharedVars.h"
#include "../ecObjects/Population.h"


namespace clbDEB {

// Selection parameters defined in this header file
#define SELECTION_SIZE "tournament-size"



//=============================================================================
//
//	Abstract class Selection
//
//=============================================================================
/**
 * This class provides the framework to implement the selection methods
 * to be used by evolutionary algorithms
 *
 * Classes inheriting from this one have to implement the method "apply"
 *
 * It will be able both to generate a new population by selecting individuals
 * from a given one, or just select one individual in the population.
 *
 * @author jjpalacios
 *
 */
class Selection {
public:
	//=========================================================================
	//		CONSTRUCTORS / INITIALIZERS
	//=========================================================================
public:
	/**
	 * Default constructor
	 */
	explicit Selection(ParameterDB *parameters=NULL);

	/**
	 * Loads the needed parameters. No default parameters needed
	 */
	virtual void setup(ParameterDB *parameters) { };

	/**
	 * Destructor
	 */
	virtual ~Selection() { }; 	// Nothing to destroy here



	//=========================================================================
	//		METHODS
	//=========================================================================
public:
	/**
	 * Get the name and setup of the operator
	 *
	 * @return A string of parameter values. The first string is the name of
	 * the operator
	 */
	virtual std::vector<std::string> getName() const = 0;

	/**
	 * Apply the selection method to choose an individual from the population
	 *
	 * @param population Population from which select an individual
	 * @param svars Shared elements of the algorithm
	 * @return The selected individual
	 */
	virtual Individual * select(Population *population,
			const SharedVars *svars) const=0;

	/**
	 * Apply the selection method to the entire population to generate
	 * a brand new one.
	 *
	 * @param population Original population of individuals
	 * @param svars Shared elements of the algorithm
	 * @return A new population with the selected individuals
	 */
	virtual Population * apply(Population *population,
			const SharedVars *svars) const;

};





//=============================================================================
//
//	Class TournamentSelection
//
//=============================================================================
/**
 * This class implements the tournament selection.
 *
 * From a given population, select K individuals at random and then takes the
 * best one.
 *
 * @author jjpalacios
 *
 */
class TournamentSelection : public Selection {
public:
	/**
	 * Name of the parameter for the size of the tournament
	 */
	std::string P_SIZE;

	/**
	 * Size of the tournament
	 */
	int size;



	//=========================================================================
	//		CONSTRUCTORS / INITIALIZERS
	//=========================================================================
public:
	/**
	 * Default constructor
	 */
	explicit TournamentSelection(ParameterDB *parameters=NULL);

	/**
	 * Loads the needed parameters: Tournament size
	 */
	virtual void setup(ParameterDB *parameters);

	/**
	 * Destructor
	 */
	virtual ~TournamentSelection() { }; 	// Nothing to destroy here



	//=========================================================================
	//		METHODS
	//=========================================================================
public:
	/**
	 * Apply the selection method to choose an individual from the population
	 *
	 * @param population Population from which select an individual
	 * @param svars Shared elements of the algorithm
	 * @return The selected individual
	 */
	virtual Individual * select(Population *population,
			const SharedVars *svars) const;

	/**
	 * Get the name and setup of the operator
	 *
	 * @return A string of parameter values. The first string is the name of
	 * the operator
	 */
	virtual std::vector<std::string> getName() const {
		std::vector<std::string> setup;
		setup.push_back("Tournament");
		setup.push_back(";Size;" + valueToString(this->size));
		return setup;
	}
};





//=============================================================================
//
//	Class RouletteSelection
//
//=============================================================================
/**
 * This class implements the roulette selection. We use the variant with
 * linear interpolation. This way we avoid issues with the scale of the
 * objective function and also when minimizing the fitness value.
 * The population is sorted according to the quality of the individuals and
 * each individual is assigned an integer value increasingly, so the best
 * individual takes value 1, and the worst one takes value "size of the population".
 *
 * @author jjpalacios
 *
 */
class RouletteSelection : public Selection {
public:
	//=========================================================================
	//		CONSTRUCTORS / INITIALIZERS
	//=========================================================================
public:
	/**
	 * Default constructor
	 */
	explicit RouletteSelection(ParameterDB *parameters=NULL)
		: Selection(parameters) { }

	/**
	 * Destructor
	 */
	virtual ~RouletteSelection() { }; 	// Nothing to destroy here



	//=========================================================================
	//		METHODS
	//=========================================================================
public:
	/**
	 * Apply the selection method to choose an individual from the population
	 *
	 * @param population Population from which select an individual
	 * @param svars Shared elements of the algorithm
	 * @return The selected individual
	 */
	virtual Individual * select(Population *population,
			const SharedVars *svars) const;


	/**
	 * Get the name and setup of the operator
	 *
	 * @return A string of parameter values. The first string is the name of
	 * the operator
	 */
	virtual std::vector<std::string> getName() const {
		std::vector<std::string> setup;
		setup.push_back("Roulette");
		return setup;
	}
};





//=============================================================================
//
//	Class SUSSelection
//
//=============================================================================
/**
 * This class implements the SUS selection. We use the variant with
 * linear interpolation. This way we avoid issues with the scale of the
 * objective function and also when minimizing the fitness value.
 * The population is sorted according to the quality of the individuals and
 * each individual is assigned an integer value increasingly, so the best
 * individual takes value 1, and the worst one takes value "size of the population".
 *
 * [J.E. Baker, “Reducing Bias and Inefficiency in the Selection Algorithm”,
 * in Genetic Algorithms and their Applications: Proc. of the 2nd Int. Conf on
 * Genetic Algorithms, pp. 14-21, 1987]
 *
 * @author jjpalacios
 *
 */
class SUSSelection : public Selection {
public:
	//=========================================================================
	//		CONSTRUCTORS / INITIALIZERS
	//=========================================================================
public:
	/**
	 * Default constructor
	 */
	explicit SUSSelection(ParameterDB *parameters=NULL)
		: Selection(parameters) { }


	/**
	 * Destructor
	 */
	virtual ~SUSSelection() { }; 	// Nothing to destroy here



	//=========================================================================
	//		METHODS
	//=========================================================================
public:
	/**
	 * The SUS algorithm is designed to create new populations, thus this
	 * method does not make sense here. In the case in which we want to select
	 * only one solution, SUS would be equivalent to the Roulette
	 *
	 * @param population Population from which select an individual
	 * @param svars Shared elements of the algorithm
	 * @return The selected individual
	 */
	virtual Individual * select(Population *population,
			const SharedVars *svars) const;

	/**
	 * Apply the selection method to the entire population to generate
	 * a brand new one following the SUS algorithm.
	 *
	 * @param population Original population of individuals
	 * @param svars Shared elements of the algorithm
	 * @return A new population with the selected individuals
	 */
	virtual Population * apply(Population *population,
			const SharedVars *svars) const;


	/**
	 * Get the name and setup of the operator
	 *
	 * @return A string of parameter values. The first string is the name of
	 * the operator
	 */
	virtual std::vector<std::string> getName() const {
		std::vector<std::string> setup;
		setup.push_back("SUS");
		return setup;
	}
};





//=============================================================================
//
//	Class ShuffleSelection
//
//=============================================================================
/**
 * This class implements the shuffle selection. In this method all the
 * individuals from the original population are selected, but changing their
 * order so they are randomly sorted in the following population
 *
 * @author jjpalacios
 *
 */
class ShuffleSelection : public Selection {
public:
	//=========================================================================
	//		CONSTRUCTORS / INITIALIZERS
	//=========================================================================
public:
	/**
	 * Default constructor
	 */
	explicit ShuffleSelection(ParameterDB *parameters=NULL)
		: Selection(parameters) { }

	/**
	 * Destructor
	 */
	virtual ~ShuffleSelection() { }; 	// Nothing to destroy here



	//=========================================================================
	//		METHODS
	//=========================================================================
public:
	/**
	 * This strategy is designed to create new populations, thus this
	 * method does not make sense here. Ii will return a random individual
	 *
	 * @param population Population from which select an individual
	 * @param svars Shared elements of the algorithm
	 * @return The selected individual
	 */
	virtual Individual * select(Population *population,
			const SharedVars *svars) const;

	/**
	 * Apply the selection method to the entire population to generate
	 * a brand new one by randomly shuffle the individuals
	 *
	 * @param population Original population of individuals
	 * @param svars Shared elements of the algorithm
	 * @return A new population with the selected individuals
	 */
	virtual Population * apply(Population *population,
			const SharedVars *svars) const;


	/**
	 * Get the name and setup of the operator
	 *
	 * @return A string of parameter values. The first string is the name of
	 * the operator
	 */
	virtual std::vector<std::string> getName() const {
		std::vector<std::string> setup;
		setup.push_back("Shuffle");
		return setup;
	}
};





//=============================================================================
//
//	Class RandomSelection
//
//=============================================================================
/**
 * This class implements a random selection. It just chooses one individual
 * at random
 *
 * @author jjpalacios
 *
 */
class RandomSelection : public Selection {
public:
	//=========================================================================
	//		CONSTRUCTORS / INITIALIZERS
	//=========================================================================
public:
	/**
	 * Default constructor
	 */
	explicit RandomSelection(ParameterDB *parameters=NULL)
		: Selection(parameters) { }

	/**
	 * Destructor
	 */
	virtual ~RandomSelection() { }; 	// Nothing to destroy here



	//=========================================================================
	//		METHODS
	//=========================================================================
public:
	/**
	 * Choose one individual at random
	 *
	 * @param population Population from which select an individual
	 * @param svars Shared elements of the algorithm
	 * @return The selected individual
	 */
	virtual Individual * select(Population *population,
			const SharedVars *svars) const;

	/**
	 * Get the name and setup of the operator
	 *
	 * @return A string of parameter values. The first string is the name of
	 * the operator
	 */
	virtual std::vector<std::string> getName() const {
		std::vector<std::string> setup;
		setup.push_back("Random");
		return setup;
	}
};


}

#endif /* SRC_ECOPERATORS_SELECTION_H_ */
