/* * 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.util.*; import org.jgap.*; import org.jgap.util.*; /** * Implementation of a NaturalSelector that takes the top n chromosomes into * the next generation. n can be specified. Which chromosomes are the best is * decided by evaluating their fitness value. * * @author Klaus Meffert * @since 1.1 */ public class BestChromosomesSelector extends NaturalSelectorExt implements ICloneable { /** String containing the CVS revision. Read out via reflection!*/ private final static String CVS_REVISION = "$Revision: 1.54 $"; /** * Stores the chromosomes to be taken into account for selection */ private Population m_chromosomes; /** * Indicated whether the list of added chromosomes needs sorting */ private boolean m_needsSorting; /** * Comparator that is concerned about both age and fitness values */ private Comparator m_fitnessValueComparator; private BestChromosomesSelectorConfig m_config = new BestChromosomesSelectorConfig(); /** * Default constructor. * Attention: The configuration used is the one set with the static method * Genotype.setConfiguration. * * @throws InvalidConfigurationException * * @author Klaus Meffert * @since 1.1 */ public BestChromosomesSelector() throws InvalidConfigurationException { this(Genotype.getStaticConfiguration()); } /** * Using original rate of 1.0 * * @param a_config the configuration to use * @throws InvalidConfigurationException * * @author Klaus Meffert * @since 3.0 */ public BestChromosomesSelector(final Configuration a_config) throws InvalidConfigurationException { this(a_config, 1.0d); } public BestChromosomesSelector(final Configuration a_config, final double a_originalRate) throws InvalidConfigurationException { super(a_config); m_chromosomes = new Population(a_config); m_needsSorting = false; setDoubletteChromosomesAllowed(true); setOriginalRate(a_originalRate); m_fitnessValueComparator = new FitnessAgeValueComparator(); } /** * Add a Chromosome instance to this selector's working pool of Chromosomes. * @param a_chromosomeToAdd the specimen to add to the pool * * @author Klaus Meffert * @since 1.1 */ protected void add(final IChromosome a_chromosomeToAdd) { // If opted-in: Check if chromosome already added // This speeds up the process by orders of magnitude but could lower the // quality of evolved results because of fewer Chromosome's used!!! if (!getDoubletteChromosomesAllowed() && m_chromosomes.getChromosomes().contains(a_chromosomeToAdd)) { return; } // New chromosome, insert it into the sorted collection of chromosomes a_chromosomeToAdd.setIsSelectedForNextGeneration(false); if (getDoubletteChromosomesAllowed()) { ICloneHandler cloner = getConfiguration().getJGAPFactory(). getCloneHandlerFor(a_chromosomeToAdd, null); if (cloner != null) { try { IChromosome clone = (IChromosome) cloner.perform( a_chromosomeToAdd, null, null); clone.setAge(a_chromosomeToAdd.getAge() + 1); m_chromosomes.addChromosome(clone); } catch (Exception ex) { ex.printStackTrace(); m_chromosomes.addChromosome(a_chromosomeToAdd); } } else { m_chromosomes.addChromosome(a_chromosomeToAdd); } } else { m_chromosomes.addChromosome(a_chromosomeToAdd); } // Indicate that the list of chromosomes to add needs sorting. // ----------------------------------------------------------- m_needsSorting = true; } /** * Selects 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_to_pop the population the chromosomes will be added to * @param a_howManyToSelect the number of chromosomes to select * * @author Klaus Meffert * @since 1.1 */ public void selectChromosomes(final int a_howManyToSelect, Population a_to_pop) { int canBeSelected; int chromsSize = m_chromosomes.size(); if (a_howManyToSelect > chromsSize) { canBeSelected = chromsSize; } else { canBeSelected = a_howManyToSelect; } int neededSize = a_howManyToSelect; double origRate; origRate = m_config.m_originalRate; if (origRate < 1.0d) { canBeSelected = (int) Math.round( (double) canBeSelected * origRate); if (canBeSelected < 1) { canBeSelected = 1; } } // Sort the collection of chromosomes previously added for evaluation. // Only do this if necessary. // ------------------------------------------------------------------- if (m_needsSorting) { Collections.sort(m_chromosomes.getChromosomes(), m_fitnessValueComparator); m_needsSorting = false; } // To select a chromosome, we just go thru the sorted list. // -------------------------------------------------------- IChromosome selectedChromosome; for (int i = 0; i < canBeSelected; i++) { selectedChromosome = m_chromosomes.getChromosome(i); selectedChromosome.setIsSelectedForNextGeneration(true); a_to_pop.addChromosome(selectedChromosome); } if (getDoubletteChromosomesAllowed()) { int toAdd; toAdd = neededSize - a_to_pop.size(); // Add existing Chromosome's to fill up the return // result to contain the desired number of Chromosome's. // ----------------------------------------------------- for (int i = 0; i < toAdd; i++) { selectedChromosome = m_chromosomes.getChromosome(i % chromsSize); ICloneHandler cloner = getConfiguration().getJGAPFactory(). getCloneHandlerFor(selectedChromosome, null); IChromosome cloned = null; if (cloner != null) { try { int age = selectedChromosome.getAge() + 1; cloned = (IChromosome) cloner.perform( selectedChromosome, null, null); cloned.setAge(age); cloned.setIsSelectedForNextGeneration(true); if(m_monitorActive) { cloned.setUniqueIDTemplate(selectedChromosome.getUniqueID(), 1); } } catch (Exception ex) { ex.printStackTrace(); } } if(cloned != null) { selectedChromosome = cloned; } a_to_pop.addChromosome(selectedChromosome); } } } /** * Empties out the working pool of Chromosomes. * * @author Klaus Meffert * @since 1.1 */ public void empty() { // clear the list of chromosomes // ----------------------------- m_chromosomes.getChromosomes().clear(); m_needsSorting = false; } /** * @return always true as no Chromosome can be returnd multiple times * * @author Klaus Meffert * @since 2.0 */ public boolean returnsUniqueChromosomes() { return true; } /** * Setting this parameter controls how many chromosomes of the original * population will be considered for selection to the next population. If * the value is 1 then the whole original population is considered, if it is * 0.5 only half of the chromosomes are considered. If doublettes are allowed, * then a number of chromosomes missing (number of to be selected minus number * selected) will be added. * @param a_originalRate the rate of how many of the original chromosomes * will be selected according to BestChromosomeSelector's strategy. The rest * (non-original) of the chromosomes is added as duplicates * * @author Klaus Meffert * @since 2.0 */ public void setOriginalRate(final double a_originalRate) { if (a_originalRate < 0.0d || a_originalRate > 1.0d) { throw new IllegalArgumentException("Original rate must be greater than" + " zero and not greater than one!"); } m_config.m_originalRate = a_originalRate; } /** * * @return see setOriginalRate * * @author Klaus Meffert * @since 2.0 */ public double getOriginalRate() { return m_config.m_originalRate; } class BestChromosomesSelectorConfig implements java.io.Serializable { /** * The rate of original Chromosomes selected. This is because we otherwise * would always return the original input as output */ public double m_originalRate; } public boolean equals(Object a_o) { if (a_o == null) { return false; } BestChromosomesSelector other = (BestChromosomesSelector) a_o; if (getDoubletteChromosomesAllowed() != other.getDoubletteChromosomesAllowed()) { return false; } if (!m_fitnessValueComparator.getClass().getName().equals( other.m_fitnessValueComparator.getClass().getName())) { return false; } if (Math.abs(m_config.m_originalRate - other.m_config.m_originalRate) > 0.001d) { return false; } if (!m_chromosomes.equals(other.m_chromosomes)) { return false; } return true; } public Object clone() { try { BestChromosomesSelector sel = new BestChromosomesSelector( getConfiguration(), m_config.m_originalRate); sel.m_needsSorting = m_needsSorting; // sel.m_chromosomes = (Population) m_chromosomes.clone(); sel.setDoubletteChromosomesAllowed(getDoubletteChromosomesAllowed()); return sel; } catch (Throwable t) { throw new CloneException(t); } } }