package cz.cvut.felk.cig.jcool.benchmark.method.evolutionary.operators.selection;
import cz.cvut.felk.cig.jcool.benchmark.method.evolutionary.Population;
import cz.cvut.felk.cig.jcool.benchmark.util.MathUtils;
import cz.cvut.felk.cig.jcool.benchmark.util.PopulationUtils;
import cz.cvut.felk.cig.jcool.benchmark.method.evolutionary.Individual;
import cz.cvut.felk.cig.jcool.core.OptimizationException;
import cz.cvut.felk.cig.jcool.core.RandomGenerator;
import org.ytoh.configurations.annotations.Component;
import java.util.ArrayList;
import java.util.List;
/**
* Created by IntelliJ IDEA.
* User: miklamar
* Date: 22.2.2011
* Time: 11:42
* Uniform deterministic selection operator. Each Individual in input population is chosen exactly n-times. Output population count and sizes have to be integral multiple of input Individuals count.
* Output arity different from 1 does not have much sense since this operator only expands each Individual by fixed times. However the individuals are mapped by columns.
* Individuals per population will be dynamically determined depending on input Individuals count, output arity and broodSize.
*/
@Component(name = "Uniform deterministic selection operator", description = "Chooses each Individual in input Populations exactly n-times")
public class UniformDeterministicSelectionOperator extends AbstractSelectionOperator{
//brood size is for internal purposes only
protected int broodSize;
public UniformDeterministicSelectionOperator(){
this.setIndividualsPerPopulation(1);
}
public Population[] select(Population[] populations) {
this.checkConsistency(populations);
// unify populations for easy linear access to all input Individuals
Individual[] inputIndividuals = this.concatenateIndividualsFromPopulations(populations, this.inputArity);
int totalOutput = inputIndividuals.length * this.broodSize;
List<Individual> outputList = new ArrayList<Individual>();
// each Individual will be selected exactly broodSize times
for (Individual individual : inputIndividuals){
for (int i = 0; i < this.broodSize; i++){
outputList.add(individual);
}
}
// preparation of output
this.individualsPerPopulation = totalOutput / this.outputArity;
Population[] outputPopulations = this.createOutputPopulations();
Individual[][] outputIndividuals = this.createOutputIndividuals();
this.mapByColumns(outputList, outputIndividuals);
this.assignIndividualsToPopulations(outputIndividuals, outputPopulations);
return outputPopulations;
}
@Override
public void checkConsistency(Population[] inputPopulations) throws OptimizationException {
super.checkConsistency(inputPopulations);
checkAlignmentPredicate(PopulationUtils.sumSizes(inputPopulations, this.inputArity));
}
/**
* Executes check for correct output population size alignment.
* @param inputIndividuals - total count of input Individuals.
*/
protected void checkAlignmentPredicate(int inputIndividuals){
int totalOutput = individualsPerPopulation * this.outputArity;
if (totalOutput % inputIndividuals != 0){
String msg = this.getClass().getSimpleName() + ": input individuals sum has to divide output arity multiplied with individuals per population. " + inputIndividuals + " does not divide " + totalOutput + ".";
throw new OptimizationException(msg);
}
this.broodSize = totalOutput / inputIndividuals;
}
protected int[] getResultsSizesCore(int[] parentPopulationSizes){
int sumSizes = MathUtils.sumSizes(parentPopulationSizes, this.getInputArity());
checkAlignmentPredicate(sumSizes);
int totalOutput = sumSizes * this.broodSize;
// set appropriate individuals per population and call super which will create output array
this.individualsPerPopulation = totalOutput / this.outputArity;
return super.getResultsSizesCore(parentPopulationSizes);
}
public void setRandomGenerator(RandomGenerator randomGenerator) {
}
public void resetGenerationCount() {
}
public void nextGeneration() {
}
public void setGeneration(int currentGeneration) {
}
}