/* Copyright 2006 by Sean Luke Licensed under the Academic Free License version 3.0 See the file "LICENSE" for more information */ package ec.steadystate; import ec.*; import ec.util.Parameter; import ec.util.Checkpoint; import ec.util.Output; import ec.simple.*; //import ec.eval.MasterProblem; import java.util.*; /* * SteadyStateEvolutionState.java * */ /** * This subclass of EvolutionState implements basic Steady-State Evolution and (in distributed form) * Asynchronous Evolution. The procedure is as follows. We begin with an empty Population and one by * one create new Indivdiuals and send them off to be evaluated. In basic Steady-State Evolution the * individuals are immediately evaluated and we wait for them; but in Asynchronous Evolution the individuals are evaluated * for however long it takes and we don't wait for them to finish. When individuals return they are * added to the Population until it is full. No duplicate individuals are allowed. * *

At this point the system switches to its "steady state": individuals are bred from the population * one by one, and sent off to be evaluated. Once again, in basic Steady-State Evolution the * individuals are immediately evaluated and we wait for them; but in Asynchronous Evolution the individuals are evaluated * for however long it takes and we don't wait for them to finish. When an individual returns, we * mark an individual in the Population for death, then replace it with the new returning individual. * Note that during the steady-state, Asynchronous Evolution could be still sending back some "new" individuals * created during the initialization phase, not "bred" individuals. * *

The determination of how an individual is marked for death is done by the SteadyStateBreeder. * *

SteadyStateEvolutionState will run either for some N "generations" or for some M evaluations of * individuals. A "generation" is defined as a Population's worth of evaluations. If you do not * specify the number of evaluations (the M), then SteadyStateEvolutionState will use the standard * generations parameter defined in EvolutionState. *

Parameters
evaluations
int >= 1
(maximal number of evaluations to run.)
* * @author Sean Luke * @version 1.0 */ public class SteadyStateEvolutionState extends EvolutionState { /** base parameter for steady-state */ public static final String P_NUMEVALUATIONS = "evaluations"; /** Did we just start a new generation? */ public boolean generationBoundary; /** How many evaluations should we run for? If set to UNDEFINED (0), we run for the number of generations instead. */ public long numEvaluations; public static long UNDEFINED = 0; /** how big is a generation? Set to the size of subpopulation 0 of the initial population. */ public int generationSize; /** How many evaluations have we run so far? */ public long evaluations; /** How many individuals have we added to the initial population? */ int[] individualCount; /** Hash table to check for duplicate individuals */ HashMap[] individualHash; /** Holds which subpopulation we are currently operating on */ int whichSubpop; /** First time calling evolve */ protected boolean firstTime; public void setup(final EvolutionState state, final Parameter base) { super.setup(state,base); // double check that we have valid evaluators and breeders and exchangers if (!(breeder instanceof SteadyStateBreeder)) state.output.error("You've chosen to use Steady-State Evolution, but your breeder is not of the class SteadyStateBreeder.",base); if (!(evaluator instanceof SteadyStateEvaluator)) state.output.error("You've chosen to use Steady-State Evolution, but your evaluator is not of the class SteadyStateEvaluator.",base); if (!(exchanger instanceof SteadyStateExchangerForm)) state.output.error("You've chosen to use Steady-State Evolution, but your exchanger does not implement the SteadyStateExchangerForm.",base); checkStatistics(state, statistics, base); numEvaluations = parameters.getLong(new Parameter(P_NUMEVALUATIONS),null,1); if (numEvaluations == 0) output.message("Number of evaluations not defined; using number of generations"); } // recursively prints out warnings for all statistics that are not // of steadystate statistics form void checkStatistics(final EvolutionState state, Statistics stat, final Parameter base) { if (!(stat instanceof SteadyStateStatisticsForm)) state.output.warning("You've chosen to use Steady-State Evolution, but your statistics does not implement the SteadyStateStatisticsForm.",base); for(int x=0;x 0 && numEvaluations < population.subpops[0].individuals.length) output.fatal("Number of evaluations desired is smaller than the initial population of individuals"); generationSize = 0; generationBoundary = false; firstTime = true; evaluations=0; whichSubpop=-1; individualHash = new HashMap[population.subpops.length]; for(int i=0;i 0) { output.message("Generation " + generation +"\tEvaluations " + evaluations); statistics.generationBoundaryStatistics(this); statistics.postEvaluationStatistics(this); } if (firstTime) { if (statistics instanceof SteadyStateStatisticsForm) ((SteadyStateStatisticsForm)statistics).enteringInitialPopulationStatistics(this); statistics.postInitializationStatistics(this); ((SteadyStateBreeder)breeder).prepareToBreed(this, 0); // unthreaded ((SteadyStateEvaluator)evaluator).prepareToEvaluate(this, 0); // unthreaded firstTime=false; } whichSubpop = (whichSubpop+1)%population.subpops.length; // round robin selection // is the current subpop full? boolean partiallyFullSubpop = (individualCount[whichSubpop] < population.subpops[whichSubpop].individuals.length); // MAIN EVOLVE LOOP if (((SteadyStateEvaluator) evaluator).canEvaluate()) // are we ready to evaluate? { Individual ind=null; int numDuplicateRetries = population.subpops[whichSubpop].numDuplicateRetries; for (int tries=0; tries <= numDuplicateRetries; tries++) // see Subpopulation { if ( partiallyFullSubpop ) // is population full? { ind = population.subpops[whichSubpop].species.newIndividual(this, 0); // unthreaded } else { ind = ((SteadyStateBreeder)breeder).breedIndividual(this, whichSubpop,0); statistics.individualsBredStatistics(this, new Individual[]{ind}); } if (numDuplicateRetries >= 1) { Object o = individualHash[whichSubpop].get(ind); if (o == null) { individualHash[whichSubpop].put(ind, ind); break; } } } // tried to cut down the duplicates // evaluate the new individual ((SteadyStateEvaluator)evaluator).evaluateIndividual(this, ind, whichSubpop); } Individual ind = ((SteadyStateEvaluator)evaluator).getNextEvaluatedIndividual(); if (ind != null) // do we have an evaluated individual? { int subpop = ((SteadyStateEvaluator)evaluator).getSubpopulationOfEvaluatedIndividual(); if ( partiallyFullSubpop ) // is subpopulation full? { population.subpops[subpop].individuals[individualCount[subpop]++]=ind; // STATISTICS FOR GENERATION ZERO if ( individualCount[subpop] == population.subpops[subpop].individuals.length ) if (statistics instanceof SteadyStateStatisticsForm) ((SteadyStateStatisticsForm)statistics).enteringSteadyStateStatistics(subpop, this); } else { // mark individual for death int deadIndividual = ((SteadyStateBreeder)breeder).deselectors[subpop].produce(subpop,this,0); Individual deadInd = population.subpops[subpop].individuals[deadIndividual]; // replace dead individual with new individual population.subpops[subpop].individuals[deadIndividual] = ind; // update duplicate hash table individualHash[subpop].remove(deadInd); if (statistics instanceof SteadyStateStatisticsForm) ((SteadyStateStatisticsForm)statistics).individualsEvaluatedStatistics(this, new Individual[]{ind}, new Individual[]{deadInd}, new int[]{subpop}, new int[]{deadIndividual}); } // INCREMENT NUMBER OF COMPLETED EVALUATIONS evaluations++; // COMPUTE GENERATION BOUNDARY generationBoundary = (evaluations % generationSize == 0); } else { generationBoundary = false; } // SHOULD WE QUIT? if (!partiallyFullSubpop && evaluator.runComplete(this) && quitOnRunComplete) { output.message("Found Ideal Individual"); return R_SUCCESS; } if ((numEvaluations > 0 && evaluations >= numEvaluations) || // using numEvaluations (numEvaluations <= 0 && generationBoundary && generation == numGenerations -1)) // not using numEvaluations { return R_FAILURE; } // EXCHANGING if (generationBoundary) { // PRE-BREED EXCHANGE statistics.prePreBreedingExchangeStatistics(this); population = exchanger.preBreedingExchangePopulation(this); statistics.postPreBreedingExchangeStatistics(this); String exchangerWantsToShutdown = exchanger.runComplete(this); if (exchangerWantsToShutdown!=null) { output.message(exchangerWantsToShutdown); return R_SUCCESS; } // POST BREED EXCHANGE statistics.prePostBreedingExchangeStatistics(this); population = exchanger.postBreedingExchangePopulation(this); statistics.postPostBreedingExchangeStatistics(this); // INCREMENT GENERATION AND CHECKPOINT generation++; if (checkpoint && generation%checkpointModulo == 0) { output.message("Checkpointing"); statistics.preCheckpointStatistics(this); Checkpoint.setCheckpoint(this); statistics.postCheckpointStatistics(this); } } return R_NOTDONE; } /** * @param result */ public void finish(int result) { /* finish up -- we completed. */ ((SteadyStateBreeder)breeder).finishPipelines(this); statistics.finalStatistics(this,result); finisher.finishPopulation(this,result); exchanger.closeContacts(this,result); evaluator.closeContacts(this,result); } }