/* * This file is part of JGAP. * * JGAP offers a dual license model containing the LGPL as well as the MPL. * * For licensing information please see the file license.txt included with JGAP * or have a look at the top of class org.jgap.Chromosome which representatively * includes the JGAP license policy applicable for any file delivered with JGAP. */ package org.jgap.impl; import java.io.*; import java.util.*; import org.jgap.*; /** * Implementation of a NaturalSelector that plays tournaments to determine * the chromosomes to be taken to the next generation. * <p> * The tournament size can be adjusted as well as the probability for selecting * an individual. * * @author Klaus Meffert * @since 2.0 */ public class TournamentSelector extends NaturalSelectorExt { /** String containing the CVS revision. Read out via reflection!*/ private final static String CVS_REVISION = "$Revision: 1.24 $"; private TournamentSelectorConfigurable m_config = new TournamentSelectorConfigurable(); private List m_chromosomes; /** * Comparator that is only concerned about fitness values */ private FitnessValueComparator m_fitnessValueComparator; /** * Default constructor.<p> * Attention: The configuration used is the one set with the static method * Genotype.setConfiguration. * * @throws InvalidConfigurationException * * @author Siddhartha Azad * @author Klaus Meffert */ public TournamentSelector() throws InvalidConfigurationException { super(Genotype.getStaticConfiguration()); init(); } private void init() { m_chromosomes = new Vector(); m_fitnessValueComparator = new FitnessValueComparator(); } /** * @param a_config the configuration to use * @param a_tournament_size the size of each tournament to play * @param a_probability probability for selecting the best individuals * * @throws InvalidConfigurationException * * @author Klaus Meffert * @since 2.0 */ public TournamentSelector(final Configuration a_config, final int a_tournament_size, final double a_probability) throws InvalidConfigurationException { super(a_config); init(); if (a_tournament_size < 1) { throw new IllegalArgumentException("Tournament size must be at least 1!"); } if (a_probability <= 0.0d || a_probability > 1.0d) { throw new IllegalArgumentException("Probability must be greater 0.0 and" + " less or equal than 1.0!"); } m_config.m_tournament_size = a_tournament_size; m_config.m_probability = a_probability; } public void setTournamentSize(final int a_tournament_size) { if (a_tournament_size < 1) { throw new IllegalArgumentException("Tournament size must be at least 1!"); } m_config.m_tournament_size = a_tournament_size; } public int getTournamentSize() { return m_config.m_tournament_size; } public double getProbability() { return m_config.m_probability; } public void setProbability(final double a_probability) { if (a_probability <= 0.0d || a_probability > 1.0d) { throw new IllegalArgumentException("Probability must be greater 0.0 and" + " less or equal than 1.0!"); } m_config.m_probability = a_probability; } /** * Select a given number of Chromosomes from the pool that will move on * to the next generation population. This selection will be guided by the * fitness values. The chromosomes with the best fitness value win. * * @param a_howManyToSelect int * @param a_to_pop the population the Chromosomes will be added to * * @author Klaus Meffert * @since 2.0 */ public void selectChromosomes(final int a_howManyToSelect, Population a_to_pop) { List tournament = new Vector(); RandomGenerator rn = getConfiguration().getRandomGenerator(); int size = m_chromosomes.size(); if (size == 0) { return; } int k; for (int i = 0; i < a_howManyToSelect; i++) { // Choose [tournament size] individuals from the population at random. // ------------------------------------------------------------------- tournament.clear(); for (int j = 0; j < m_config.m_tournament_size; j++) { k = rn.nextInt(size); tournament.add(m_chromosomes.get(k)); } Collections.sort(tournament, m_fitnessValueComparator); double prob = rn.nextDouble(); double probAccumulated = m_config.m_probability; int index = 0; // Play the tournament. // -------------------- if (m_config.m_tournament_size > 1) { do { if (prob <= probAccumulated) { break; } else { probAccumulated += probAccumulated * (1 - m_config.m_probability); index++; } } while (index < m_config.m_tournament_size - 1); } a_to_pop.addChromosome( (IChromosome) tournament.get(index)); } } /** * @return false as we allow to return the same chromosome multiple times * * @author Klaus Meffert * @since 2.0 */ public boolean returnsUniqueChromosomes() { return false; } public void empty() { m_chromosomes.clear(); } /** * * @param a_chromosomeToAdd the chromosome to add * * @author Klaus Meffert * @since 2.0 */ protected void add(final IChromosome a_chromosomeToAdd) { m_chromosomes.add(a_chromosomeToAdd); } /** * Comparator regarding only the fitness value. Best fitness value will * be on first position of resulting sorted list. * * @author Klaus Meffert * @since 2.0 */ private class FitnessValueComparator implements Comparator { public FitnessValueComparator() { } public int compare(final Object a_first, final Object a_second) { IChromosome chrom1 = (IChromosome) a_first; IChromosome chrom2 = (IChromosome) a_second; if (getConfiguration().getFitnessEvaluator().isFitter(chrom2. getFitnessValue(), chrom1.getFitnessValue())) { return 1; } else if (getConfiguration().getFitnessEvaluator().isFitter( chrom1.getFitnessValue(), chrom2.getFitnessValue())) { return -1; } else { return 0; } } } class TournamentSelectorConfigurable implements Serializable { /** * The probability for selecting the best chromosome in a tournament. * For the second-best chromosome it would be p * (1 - p). * For the third-best chromosome it would be p * (p * (1 - p)) and so forth. */ public double m_probability; /** * Size of a tournament to be played, i.e. number of chromosomes taken into * account for one selection round */ public int m_tournament_size; } }