/* * 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 org.jgap.*; import org.jgap.audit.*; import org.jgap.event.*; public class GABreeder extends BreederBase { /** String containing the CVS revision. Read out via reflection!*/ private final static String CVS_REVISION = "$Revision: 1.17 $"; private transient Configuration m_lastConf; private transient Population m_lastPop; public GABreeder() { super(); } /** * Evolves the population of chromosomes within a genotype. This will * execute all of the genetic operators added to the present active * configuration and then invoke the natural selector to choose which * chromosomes will be included in the next generation population. * * @param a_pop the population to evolve * @param a_conf the configuration to use for evolution * * @return evolved population * * @author Klaus Meffert * @since 3.2 */ public Population evolve(Population a_pop, Configuration a_conf) { Population pop = a_pop; int originalPopSize = a_conf.getPopulationSize(); boolean monitorActive = a_conf.getMonitor() != null; IChromosome fittest = null; // If first generation: Set age to one to allow genetic operations, // see CrossoverOperator for an illustration. // ---------------------------------------------------------------- if (a_conf.getGenerationNr() == 0) { int size = pop.size(); for (int i = 0; i < size; i++) { IChromosome chrom = pop.getChromosome(i); chrom.increaseAge(); } } else { // Select fittest chromosome in case it should be preserved and we are // not in the very first generation. // ------------------------------------------------------------------- if (a_conf.isPreserveFittestIndividual()) { /**@todo utilize jobs. In pop do also utilize jobs, especially for fitness * computation*/ fittest = pop.determineFittestChromosome(0, pop.size() - 1); } } if (a_conf.getGenerationNr() > 0) { // Adjust population size to configured size (if wanted). // Theoretically, this should be done at the end of this method. // But for optimization issues it is not. If it is the last call to // evolve() then the resulting population possibly contains more // chromosomes than the wanted number. But this is no bad thing as // more alternatives mean better chances having a fit candidate. // If it is not the last call to evolve() then the next call will // ensure the correct population size by calling keepPopSizeConstant. // ------------------------------------------------------------------ keepPopSizeConstant(pop, a_conf); } // Ensure fitness value of all chromosomes is udpated. // --------------------------------------------------- if (monitorActive) { // Monitor that fitness value of chromosomes is being updated. // ----------------------------------------------------------- a_conf.getMonitor().event( IEvolutionMonitor.MONITOR_EVENT_BEFORE_UPDATE_CHROMOSOMES1, a_conf.getGenerationNr(), new Object[]{pop}); } updateChromosomes(pop, a_conf); if (monitorActive) { // Monitor that fitness value of chromosomes is being updated. // ----------------------------------------------------------- a_conf.getMonitor().event( IEvolutionMonitor.MONITOR_EVENT_AFTER_UPDATE_CHROMOSOMES1, a_conf.getGenerationNr(), new Object[]{pop}); } // Apply certain NaturalSelectors before GeneticOperators will be executed. // ------------------------------------------------------------------------ pop = applyNaturalSelectors(a_conf, pop, true); // Execute all of the Genetic Operators. // ------------------------------------- applyGeneticOperators(a_conf, pop); // Reset fitness value of genetically operated chromosomes. // Normally, this should not be necessary as the Chromosome class // initializes each newly created chromosome with // FitnessFunction.NO_FITNESS_VALUE. But who knows which Chromosome // implementation is used... // ---------------------------------------------------------------- int currentPopSize = pop.size(); for (int i = originalPopSize; i < currentPopSize; i++) { IChromosome chrom = pop.getChromosome(i); chrom.setFitnessValueDirectly(FitnessFunction.NO_FITNESS_VALUE); // Mark chromosome as new-born. // ---------------------------- chrom.resetAge(); // Mark chromosome as being operated on. // ------------------------------------- chrom.increaseOperatedOn(); } // Increase age of all chromosomes which are not modified by genetic // operations. // ----------------------------------------------------------------- int size = Math.min(originalPopSize, currentPopSize); for (int i = 0; i < size; i++) { IChromosome chrom = pop.getChromosome(i); chrom.increaseAge(); // Mark chromosome as not being operated on. // ----------------------------------------- chrom.resetOperatedOn(); } // If a bulk fitness function has been provided, call it. // ------------------------------------------------------ BulkFitnessFunction bulkFunction = a_conf.getBulkFitnessFunction(); if (bulkFunction != null) { if (monitorActive) { // Monitor that bulk fitness will be called for evaluation. // -------------------------------------------------------- a_conf.getMonitor().event( IEvolutionMonitor.MONITOR_EVENT_BEFORE_BULK_EVAL, a_conf.getGenerationNr(), new Object[] {bulkFunction, pop}); } /**@todo utilize jobs: bulk fitness function is not so important for a * prototype! */ bulkFunction.evaluate(pop); if (monitorActive) { // Monitor that bulk fitness has been called for evaluation. // --------------------------------------------------------- a_conf.getMonitor().event( IEvolutionMonitor.MONITOR_EVENT_AFTER_BULK_EVAL, a_conf.getGenerationNr(), new Object[] {bulkFunction, pop}); } } // Ensure fitness value of all chromosomes is udpated. // --------------------------------------------------- if (monitorActive) { // Monitor that fitness value of chromosomes is being updated. // ----------------------------------------------------------- a_conf.getMonitor().event( IEvolutionMonitor.MONITOR_EVENT_BEFORE_UPDATE_CHROMOSOMES2, a_conf.getGenerationNr(), new Object[]{pop}); } updateChromosomes(pop, a_conf); if (monitorActive) { // Monitor that fitness value of chromosomes is being updated. // ----------------------------------------------------------- a_conf.getMonitor().event( IEvolutionMonitor.MONITOR_EVENT_AFTER_UPDATE_CHROMOSOMES2, a_conf.getGenerationNr(), new Object[]{pop}); } // Apply certain NaturalSelectors after GeneticOperators have been applied. // ------------------------------------------------------------------------ pop = applyNaturalSelectors(a_conf, pop, false); // Fill up population randomly if size dropped below specified percentage // of original size. // ---------------------------------------------------------------------- if (a_conf.getMinimumPopSizePercent() > 0) { int sizeWanted = a_conf.getPopulationSize(); int popSize; int minSize = (int) Math.round(sizeWanted * (double) a_conf.getMinimumPopSizePercent() / 100); popSize = pop.size(); if (popSize < minSize) { IChromosome newChrom; IChromosome sampleChrom = a_conf.getSampleChromosome(); Class sampleChromClass = sampleChrom.getClass(); IInitializer chromIniter = a_conf.getJGAPFactory(). getInitializerFor(sampleChrom, sampleChromClass); while (pop.size() < minSize) { try { /**@todo utilize jobs as initialization may be time-consuming as * invalid combinations may have to be filtered out*/ newChrom = (IChromosome) chromIniter.perform(sampleChrom, sampleChromClass, null); if (monitorActive) { // Monitor that fitness value of chromosomes is being updated. // ----------------------------------------------------------- a_conf.getMonitor().event( IEvolutionMonitor.MONITOR_EVENT_BEFORE_ADD_CHROMOSOME, a_conf.getGenerationNr(), new Object[]{pop, newChrom}); } pop.addChromosome(newChrom); } catch (Exception ex) { throw new RuntimeException(ex); } } } } IChromosome newFittest = reAddFittest(pop, fittest); if (monitorActive && newFittest != null) { // Monitor that fitness value of chromosomes is being updated. // ----------------------------------------------------------- a_conf.getMonitor().event( IEvolutionMonitor.MONITOR_EVENT_READD_FITTEST, a_conf.getGenerationNr(), new Object[] {pop, fittest}); } // Increase number of generations. // ------------------------------- a_conf.incrementGenerationNr(); // Fire an event to indicate we've performed an evolution. // ------------------------------------------------------- m_lastPop = pop; m_lastConf = a_conf; a_conf.getEventManager().fireGeneticEvent( new GeneticEvent(GeneticEvent.GENOTYPE_EVOLVED_EVENT, this)); return pop; } public Configuration getLastConfiguration() { return m_lastConf; } public Population getLastPopulation() { return m_lastPop; } /** * @return deep clone of this instance * * @author Klaus Meffert * @since 3.2 */ public Object clone() { return new GABreeder(); } /** * Cares that population size is kept constant and does not exceed the desired * size. * * @param a_pop Population * @param a_conf Configuration */ protected void keepPopSizeConstant(Population a_pop, Configuration a_conf) { if (a_conf.isKeepPopulationSizeConstant()) { try { a_pop.keepPopSizeConstant(); } catch (InvalidConfigurationException iex) { throw new RuntimeException(iex); } } } protected IChromosome reAddFittest(Population a_pop, IChromosome a_fittest) { // Determine if all-time fittest chromosome is in the population. // -------------------------------------------------------------- if (a_fittest != null && !a_pop.contains(a_fittest)) { // Re-add fittest chromosome to current population. // ------------------------------------------------ a_pop.addChromosome(a_fittest); return a_fittest; } return null; } protected void updateChromosomes(Population a_pop, Configuration a_conf) { int currentPopSize = a_pop.size(); // Ensure all chromosomes are updated. // ----------------------------------- BulkFitnessFunction bulkFunction = a_conf.getBulkFitnessFunction(); boolean bulkFitFunc = (bulkFunction != null); if (!bulkFitFunc) { for (int i = 0; i < currentPopSize; i++) { IChromosome chrom = a_pop.getChromosome(i); chrom.getFitnessValue(); } } } }