/*
 * Mutation.cpp
 *
 *  Created on: Jul 27, 2015
 *      Author: jjpalacios
 */

#include "./Mutation.h"

namespace clbDEB {

//=============================================================================
//
//	Abstract class Mutation
//
//=============================================================================
//=============================================================================
//		CONSTRUCTORS / INITIALIZERS
//=============================================================================
//-----  Main constructor  ----------------------------------------------------
Mutation::Mutation(ParameterDB *parameters) {
	this->P_PROB = MUTATION_PROBABILITY;
	this->probability = -1.0;
	if(parameters != NULL)
		this->setup(parameters);
}

//-----  Setup method  ----------------------------------------------------
void Mutation::setup(ParameterDB *parameters) {
	this->probability = parameters->getDouble(this->P_PROB, -1.0);
	if(this->probability < 0 || this->probability > 1) {
		std::string err = "Invalid mutation probability.";
		err += " Incorrect value or missing parameter.";
		throw ClbException(err);
	}
}



//=============================================================================
//		METHODS
//=============================================================================
//-----  Apply (Population)  --------------------------------------------------
void Mutation::apply(Population *population, const SharedVars *svars) const {
	for(int i=0; i < population->size(); i++) {
		if(svars->rng->getProbability() < this->probability)
			apply(population->individual(i), svars);
	}
}





//=============================================================================
//
//	Class RandomMutation
//
//=============================================================================
//-----  Main constructor  ----------------------------------------------------
RandomMutation::RandomMutation(ParameterDB *parameters) : Mutation() {
	this->P_PROB_GENE = MUTATION_GENE_PROBABILITY;
	this->prob_gene = -1.0;
	if(parameters != NULL)
			this->setup(parameters);
}

//-----  Main constructor  ----------------------------------------------------
void RandomMutation::setup(ParameterDB *parameters) {
	// Load the parameters of your parent
	Mutation::setup(parameters);

	// Load own parameters
	this->prob_gene = parameters->getDouble(this->P_PROB_GENE, -1.0);
	if(this->prob_gene < 0 || this->prob_gene > 1) {
		std::string err = "Invalid mutation probability per gene.";
		err += " Incorrect value or missing parameter.";
		throw ClbException(err);
	}
}



//=========================================================================
//		METHODS
//=========================================================================
//-----  Apply (Individual)  ----------------------------------------------
void RandomMutation::apply(Individual *individual,
		const SharedVars *svars) const {
	// If the individual is made of integer values
	if(individual->getType() == INTEGER_INDIVIDUAL) {
		IntegerIndividual * ind = dynamic_cast<IntegerIndividual *>(individual);

		for(int i=0; i < ind->length(); i++) {
			if(svars->rng->getProbability() < this->prob_gene) {
				int rnd = svars->rng->getInteger(
						svars->minGene[i], svars->maxGene[i]);
				ind->setGene(i, rnd);
			}
		}
	}

	// Else, if the individual is made of double values
	else if(individual->getType() == DOUBLE_INDIVIDUAL) {
		DoubleIndividual * ind = dynamic_cast<DoubleIndividual *>(individual);

		for(int i=0; i < ind->length(); i++) {
			if(svars->rng->getProbability() < this->prob_gene) {
				double rnd = svars->rng->getDouble(
						svars->minGene[i], svars->maxGene[i]);
				ind->setGene(i, rnd);
			}
		}
	}
}





//=============================================================================
//
//	Class ExtremeMutation
//
//=============================================================================
//-----  Main constructor  ----------------------------------------------------
ExtremeMutation::ExtremeMutation(ParameterDB *parameters) : Mutation() {
	this->P_PROB_GENE = MUTATION_GENE_PROBABILITY;
	this->prob_gene = -1.0;
	if(parameters != NULL)
			this->setup(parameters);
}

//-----  Main constructor  ----------------------------------------------------
void ExtremeMutation::setup(ParameterDB *parameters) {
	// Load the parameters of your parent
	Mutation::setup(parameters);

	// Load own parameters
	this->prob_gene = parameters->getDouble(this->P_PROB_GENE, -1.0);
	if(this->prob_gene < 0 || this->prob_gene > 1) {
		std::string err = "Invalid mutation probability per gene.";
		err += " Incorrect value or missing parameter.";
		throw ClbException(err);
	}
}



//=========================================================================
//		METHODS
//=========================================================================
//-----  Apply (Individual)  ----------------------------------------------
void ExtremeMutation::apply(Individual *individual,
		const SharedVars *svars) const {
	// If the individual is made of integer values
	if(individual->getType() == INTEGER_INDIVIDUAL) {
		IntegerIndividual * ind = dynamic_cast<IntegerIndividual *>(individual);

		for(int i=0; i < ind->length(); i++) {
			if(svars->rng->getProbability() < this->prob_gene) {
				if(svars->rng->getProbability() < 0.5)
					ind->setGene(i, (int)svars->minGene[i]);
				else
					ind->setGene(i, (int)svars->maxGene[i]);
			}
		}
	}

	// Else, if the individual is made of double values
	else if(individual->getType() == DOUBLE_INDIVIDUAL) {
		DoubleIndividual * ind = dynamic_cast<DoubleIndividual *>(individual);

		for(int i=0; i < ind->length(); i++) {
			if(svars->rng->getProbability() < this->prob_gene) {
				if(svars->rng->getProbability() < 0.5)
					ind->setGene(i, svars->minGene[i]);
				else
					ind->setGene(i, svars->maxGene[i]);
			}
		}
	}
}


}


