/*
* File: TournamentSelector.java
* Authors: Jonathan McClain
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright May 4, 2006, Sandia Corporation. Under the terms of Contract
* DE-AC04-94AL85000, there is a non-exclusive license for use of this work by
* or on behalf of the U.S. Government. Export of this program may require a
* license from the United States Government. See CopyrightHistory.txt for
* complete details.
*
*
*/
package gov.sandia.cognition.learning.algorithm.genetic.selector;
import gov.sandia.cognition.annotation.CodeReview;
import gov.sandia.cognition.annotation.CodeReviews;
import gov.sandia.cognition.learning.algorithm.genetic.EvaluatedGenome;
import gov.sandia.cognition.util.Randomized;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;
/**
* The TournamentSelector class implements a Selector that uses tournament
* selection to create a new population.
* <BR><BR>
* The tournament selector selects each member of the population by having
* a tournament of the given tournament size. The winner of that tournament
* (the genome with the lowest cost) is then entered into the selected
* population. This allows
*
* @param <GenomeType> Type of genome used to represent a single element in the
* genetic population, such as a Vector, for example
* @author Justin Basilico
* @author Jonathan McClain
* @since 1.0
*/
@CodeReviews(
reviews={
@CodeReview(
reviewer="Kevin R. Dixon",
date="2008-07-23",
changesNeeded=false,
comments={
"Now implements Randomized.",
"Moved previous code review as CodeReview annotation",
"Looks fine."
}
)
,
@CodeReview(
reviewer="Justin Basilico",
date="2006-10-04",
changesNeeded=false,
comments={
"I optimized the code to make it faster and use less memory.",
"I also made the Random object a parameter of the class, not generated each time select is called."
}
)
}
)
public class TournamentSelector<GenomeType>
extends AbstractSelector<GenomeType>
implements Randomized
{
/** The percent of the population to select. */
private double percent = 0.0;
/** The size of the tournament. */
private int tournamentSize = 0;
/** The random number generator to use. */
private Random random = null;
/**
* Creates a new instance of TournamentSelector.
*
* @param percent The percent of the population to select.
* @param tournamentSize The size of each tournament when selecting.
*/
public TournamentSelector(
double percent,
int tournamentSize)
{
this(percent, tournamentSize, new Random());
}
/**
* Creates a new instance of TournamentSelector.
*
* @param percent The percent of the population to select.
* @param tournamentSize The size of each tournament when selecting.
* @param random The random number generator to use.
*/
public TournamentSelector(
double percent,
int tournamentSize,
Random random)
{
super();
this.setPercent(percent);
this.setTournamentSize(tournamentSize);
this.setRandom(random);
}
/**
* Uses tournament selection to create a new population.
*
* @param genomes The population to select from.
* @return The selected population.
*/
public Collection<EvaluatedGenome<GenomeType>> select(
Collection<EvaluatedGenome<GenomeType>> genomes)
{
// Convert the population to an array list to make it fast.
ArrayList<EvaluatedGenome<GenomeType>> population;
if( genomes instanceof ArrayList )
{
population = (ArrayList<EvaluatedGenome<GenomeType>>) genomes;
}
else
{
population = new ArrayList<EvaluatedGenome<GenomeType>>(genomes);
}
int numToCreate = (int) Math.round(
(double) population.size() * this.getPercent());
ArrayList<EvaluatedGenome<GenomeType>> selectedPopulation =
new ArrayList<EvaluatedGenome<GenomeType>>(numToCreate);
int tournySize = this.getTournamentSize();
int numGenomes = genomes.size();
Random rng = this.getRandom();
// Loop through the number to create and create that many tournaments.
for (int i = 0; i < numToCreate; i++)
{
// Conduct the tournament to select the next member of the
// population.
EvaluatedGenome<GenomeType> winner = null;
for (int j = 0; j < tournySize; j++)
{
// Select a random genome.
int randomIndex = rng.nextInt(numGenomes);
EvaluatedGenome<GenomeType> genome =
population.get(randomIndex);
if ( winner == null || genome.getCost() < winner.getCost() )
{
// This is the best seen so far.
winner = genome;
}
}
// Add the winner of the tournament.
selectedPopulation.add(winner);
}
// Return the selected population.
return selectedPopulation;
}
/**
* Gets the percent of the population to select.
*
* @return The percent.
*/
public double getPercent()
{
return this.percent;
}
/**
* Gets the size for tournaments.
*
* @return The size.
*/
public int getTournamentSize()
{
return this.tournamentSize;
}
/**
* Gets the random number generator being used.
*
* @return The random number generator being used.
*/
public Random getRandom()
{
return this.random;
}
/**
* Sets the percent of the population to select.
*
* @param percent The new percent.
*/
public void setPercent(
double percent)
{
if ( percent <= 0.0 )
{
throw new IllegalArgumentException(
"The percentage must be positive.");
}
this.percent = percent;
}
/**
* Sets the size for tournaments.
*
* @param tournamentSize The new size.
*/
public void setTournamentSize(
int tournamentSize)
{
if ( tournamentSize <= 0 )
{
throw new IllegalArgumentException(
"The tournament size must be positive.");
}
this.tournamentSize = tournamentSize;
}
/**
* Sets the random number generator to use.
*
* @param random The new random number generator.
*/
public void setRandom(
Random random)
{
this.random = random;
}
}