/*
 * GeneticAlgorithm.h
 *
 *  Created on: Jul 28, 2015
 *      Author: jjpalacios
 */

#ifndef SRC_ECMETHODS_NICHEGENETIC_H_
#define SRC_ECMETHODS_NICHEGENETIC_H_



#include "../heading.h"
#include "../ClassRegister.h"
#include "../ecObjects/Population.h"
#include "../ecObjects/Statistics.h"
#include "./MultimodalAlgorithm.h"


namespace clbDEB {


// Parameters defined in this header file
#define NGA_CROSSOVER "crossover"	// Crossover operator
#define NGA_MUTATION "mutation"		// Mutation operator
#define NGA_SELECTION "selection"	// Selection operator
#define NGA_REPLACE "replacement"	// Replacement operator
#define NGA_CREATION "creation"	// Replacement operator

#define NGA_GENERATIONS "generations"	// Maximum number of iterations
#define NGA_TIME "time-limit"			// Maximum runtime
#define NGA_EVALUATIONS "evaluations"	// Maximum number of evaluations

#define NGA_POP_SIZE "pop-size"			// Population size
#define NGA_INDIVIDUAL_TYPE "gene-type"	// Type of individual (integer or real)

#define NGA_NICHE_CAPACITY "niche-capacity"	// Niche capacity
#define NGA_NICHE_RADIUS "niche-radius"	// Niche radius
#define NGA_NICHE_STRATEGY "niche-strategy"	// Clearing or sharing

#define NGA_NICHE_CLEARING "clearing"	// Clearing
#define NGA_NICHE_SHARING "sharing"	// sharing

#define NGA_PRINT_POPULATION "print-population"	// Shall we print the population?
#define NGA_POP_INTERVAL "print-population.generations"	// Number of generations between printing populations

enum Niching_Strategy { CLEARING, SHARING };



//=============================================================================
//
//	Class NicheGenetic
//
//=============================================================================
/**
 * This class implements niche genetic algorithms.
 *
 * It allows both clearing and sharing strategies.
 *
 * @author jjpalacios
 *
 */
class NicheGenetic : public MultimodalAlgorithm {
	//=========================================================================
	//		FIELDS
	//=========================================================================
protected:
	//-----  CONFIGURATION FIELDS  ------------------------
	/**
	 * Genetic operators
	 */
	Crossover * crossover;
	Mutation * mutation;

	/**
	 * Initial popuations
	 */
	Creation * creation;

	/**
	 * Selection operator
	 */
	Selection * selection;

	/**
	 * Replacement strategy
	 */
	Replacement * replacement;

	/**
	 * Different stopping criteria
	 */
	int maxGenerations;
	int maxEvaluations;
	double maxRuntime;

	/**
	 * Population size
	 */
	int populationSize;

	/**
	 * Individual type
	 */
	typeOfIndividual typeIndividual;

	/**
	 * Niche parameters
	 */
	double nicheRadius;
	int nicheCapacity;
	Niching_Strategy niching;

	/**
	 * Printing population parameters
	 */
	bool printPopulation;
	int printPopGenerations;





	//-----  DYNAMIC FIELDS  ------------------------------
	/**
	 * Current status
	 */
	int generation;
	int evaluations;
	Individual *bestSoFar;

	/**
	 * Runtimes
	 */
	clock_t totalRuntime;
	clock_t creationTime;
	clock_t selectionTime;
	clock_t crossoverTime;
	clock_t mutationTime;
	clock_t replacementTime;
	clock_t nichingTime;
	clock_t evaluationTime;

	/**
	 * Evolution data for statistics
	 */
	std::vector< std::vector<double> > evolutionStats;





	//=========================================================================
	//		CONSTRUCTORS / INITIALIZERS
	//=========================================================================
public:
	/**
	 * Constructor using the parameters file.
	 * Reads the parameters file, but does not initialize objects
	 */
	explicit NicheGenetic(const char * setupFile);

	/**
	 * Destructor
	 */
	virtual ~NicheGenetic();

protected:
	/**
	 * Destroys everything
	 */
	virtual void clearAll();


	//=========================================================================
	//		GET/SET METHODS
	//=========================================================================
public:
	/**
	 * This method prints the configuration of the algorithm in CSV format
	 * and using a tree structure for a better understanding
	 *
	 * @return A string of parameter values. The first string is the name of
	 * the operator
	 */
	virtual void printSetupTree(std::ofstream & output) const;


	/**
	 * Returns the basic statistics provided by the algorithm
	 *
	 * @return An array of pairs with the name of the statistic and its value
	 */
	virtual std::vector< std::pair<std::string, double> > getStatistics() const;

	/**
	 * Returns the time employed by each component of the algorithm
	 *
	 * @return An array of pairs with the name of the component and the time
	 * consumed. The first component is always the total runtime
	 */
	virtual std::vector< std::pair<std::string, double> > getRuntime() const;

	/**
	 * Returns the evolution of the algorithm during the run
	 *
	 * @param labels Output variable to store the name of each evolution
	 * component
	 * @return A matrix with the evolution of different elements
	 */
	virtual std::vector< std::vector<double> > getEvolution(
			std::vector< std::string > &labels) const;



	//=========================================================================
	//		METHODS
	//=========================================================================
public:
	/**
	 * Creates all the objects that are needed by the algorithm from the
	 * configuration stored in the ParameterDB object. This must be called
	 * the first time we want to run the algorithm. If a parameter is changed
	 * between the runs, it must be called again
	 */
	virtual void prepareToRun();


	/**
	 * Run the algorithm
	 *
	 * @return A set of solutions
	 */
	virtual Results * run(std::string signature, std::string logFolder,
			int rngSeed);

protected:
	/**
	 * Check that the algorithm is setup and ready to run.
	 * If any object is not correctly initialized, this produces an
	 * exception so the algorithm stops before going any further
	 *
	 * @return true if all components are correctly initialized
	 */
	virtual bool checkSetup();

	/**
	 * Apply the clearing strategy to an evaluated population
	 *
	 * @param population Population to which apply the clearing
	 * @return The number of niches in the population
	 */
	virtual int clearing(Population *population);

	/**
	 * Apply the sharing strategy to an evaluated population
	 *
	 * @param population Population to which apply the sharing
	 * @return 0
	 */
	virtual int sharing(Population *population);


	/**
	 * Indicates if the stopping criteria has been met
	 *
	 * @return true if the stopping criteria is met
	 */
	virtual bool stop();
};

}

#endif /* SRC_ECMETHODS_NICHEGENETIC_H_ */
