package bsearch.algorithms;
import java.util.Arrays;
import java.util.HashMap;
import org.nlogo.util.MersenneTwisterFast;
import bsearch.app.BehaviorSearchException;
import bsearch.app.SearchProtocol;
import bsearch.evaluation.SearchManager;
import bsearch.nlogolink.NetLogoLinkException;
import bsearch.representations.Chromosome;
import bsearch.representations.ChromosomeFactory;
import bsearch.space.SearchSpace;
public strictfp class StandardGA extends AbstractSearchMethod{
private double mutationRate = 0.01;
private double crossoverRate = 0.7;
private int populationSize = 50;
private int tournamentSize = 3;
private String populationModel = "generational";
public StandardGA()
{
}
public String getName()
{
return "StandardGA";
}
public String getDescription()
{
return "A standard Genetic Algorithm.";
}
public void setSearchParams( HashMap<String , String> searchMethodParams ) throws SearchParameterException
{
mutationRate = validDoubleParam(searchMethodParams, "mutation-rate", 0.0, 1.0);
crossoverRate = validDoubleParam(searchMethodParams, "crossover-rate", 0.0, 1.0);
populationSize = validIntParam(searchMethodParams, "population-size", 2, 1000);
tournamentSize = validIntParam(searchMethodParams, "tournament-size", 2, 10);
populationModel = validChoiceParam(searchMethodParams, "population-model", Arrays.asList("generational","steady-state-replace-random","steady-state-replace-worst"));
}
public HashMap<String , String> getSearchParams()
{
HashMap<String,String> params = new HashMap<String,String>();
params.put("mutation-rate", Double.toString( mutationRate ));
params.put("crossover-rate", Double.toString( crossoverRate ));
params.put("population-size", Integer.toString( populationSize ));
params.put("tournament-size", Integer.toString( tournamentSize ));
params.put("population-model", populationModel);
return params;
}
public HashMap<String , String> getSearchParamsHelp()
{
HashMap<String,String> params = new HashMap<String,String>();
params.put("mutation-rate", "likelihood of mutation occurring in each child");
params.put("crossover-rate", "probability of using two parents to create a child (otherwise child is created asexually)");
params.put("population-size", "the number of individuals in each generation");
params.put("tournament-size", "for tournament selection, this is the number of individuals that compete to choose an individual that gets to reproduce." );
params.put("population-model", "'generational', 'steady-state-replace-random', or 'steady-state-replace-worst' -- generational means the whole population is replaced at once, whereas steady-state means that just a single individual is replaced by reproduction each iteration - either a randomly-chosen individual, or the current worst." );
return params;
}
public void search( SearchSpace space , ChromosomeFactory cFactory, SearchProtocol protocol ,
SearchManager manager, MersenneTwisterFast rng )
throws BehaviorSearchException, NetLogoLinkException, InterruptedException
{
Chromosome[] population = new Chromosome[populationSize];
for (int i = 0; i < populationSize; i++)
{
population[i] = cFactory.createChromosome(space, rng);
}
double[] fitness = manager.computeFitnessBatch(population, protocol.fitnessSamplingReplications, rng);
if (populationModel.equals("generational"))
{
Chromosome[] newpopulation = new Chromosome[populationSize];
while ( !manager.searchFinished() )
{
int crossoverPairs = (int) (crossoverRate * populationSize / 2) ;
int newPopIndex = 0;
for (int i = 0; i < crossoverPairs; i++)
{
Chromosome p1 = manager.tournamentSelect(population, fitness, tournamentSize, rng);
Chromosome p2 = manager.tournamentSelect(population, fitness, tournamentSize, rng);
Chromosome[] children = p1.crossoverWith( p2 , rng ) ;
newpopulation[newPopIndex++] = children[0];
newpopulation[newPopIndex++] = children[1];
}
while (newPopIndex < populationSize)
{
newpopulation[newPopIndex++] = manager.tournamentSelect(population, fitness, tournamentSize, rng);
}
for (int i = 0; i < populationSize; i++)
{
newpopulation[i] = newpopulation[i].mutate( mutationRate , rng );
}
// swap in new population
Chromosome[] temp = population;
population = newpopulation;
newpopulation = temp;
fitness = manager.computeFitnessBatch(population, protocol.fitnessSamplingReplications, rng);
}
}
else if (populationModel.startsWith("steady-state"))
{
while ( !manager.searchFinished() )
{
Chromosome child = manager.tournamentSelect(population, fitness, tournamentSize, rng);;
if (rng.nextDouble() < crossoverRate)
{
Chromosome p2 = manager.tournamentSelect(population, fitness, tournamentSize, rng);
child = child.crossoverWith( p2 , rng )[0] ;
}
child = child.mutate(mutationRate, rng);
double childFitness = manager.computeFitnessSingle(child, protocol.fitnessSamplingReplications, rng);
int replaceIndex;
if (populationModel.equals("steady-state-replace-random"))
{
replaceIndex = rng.nextInt(populationSize);
}
else
{
double worstFitness = fitness[0];
replaceIndex = 0;
for (int i = 0; i < populationSize; i++)
{
if (manager.fitnessStrictlyBetter(worstFitness, fitness[i]))
{
replaceIndex = i;
worstFitness = fitness[i];
}
}
}
population[replaceIndex] = child;
fitness[replaceIndex] = childFitness;
}
}
}
}