/*
  Copyright 2006 by Sean Luke
  Licensed under the Academic Free License version 3.0
  See the file "LICENSE" for more information
*/


package ec.simple;
import ec.Initializer;
import ec.Individual;
import ec.BreedingPipeline;
import ec.Breeder;
import ec.EvolutionState;
import ec.Population;
import ec.util.Parameter;
import ec.util.*;

/* 
 * SimpleBreeder.java
 * 
 * Created: Tue Aug 10 21:00:11 1999
 * By: Sean Luke
 */

/**
 * Breeds each subpopulation separately, with no inter-population exchange,
 * and using a generational approach.  A SimpleBreeder may have multiple
 * threads; it divvys up a subpopulation into chunks and hands one chunk
 * to each thread to populate.  One array of BreedingPipelines is obtained
 * from a population's Species for each operating breeding thread.
 *
 * 

Prior to breeding a subpopulation, a SimpleBreeder may first fill part of the new * subpopulation up with the best n individuals from the old subpopulation. * By default, n is 0 for each subpopulation (that is, this "elitism" * is not done). The elitist step is performed by a single thread. * *

If the sequential parameter below is true, then breeding is done specially: * instead of breeding all Subpopulations each generation, we only breed one each generation. * The subpopulation index to breed is determined by taking the generation number, modulo the * total number of subpopulations. Use of this parameter outside of a coevolutionary context * (see ec.coevolve.MultiPopCoevolutionaryEvaluator) is very rare indeed. * *

SimpleBreeder adheres to the default-subpop parameter in Population: if either an 'elite' * or 'reevaluate-elites' parameter is missing, it will use the default subpopulation's value * and signal a warning. *

Parameters

base.elite.i
int >= 0 (default=0)
(the number of elitist individuals for subpopulation i)
base.reevaluate-elites.i
boolean (default = false)
(should we reevaluate the elites of subpopulation i each generation?)
base.sequential
boolean (default = false)
(should we breed just one subpopulation each generation (as opposed to all of them)?)
* * * @author Sean Luke * @version 1.0 */ public class SimpleBreeder extends Breeder { public static final String P_ELITE = "elite"; public static final String P_ELITE_FRAC = "elite-fraction"; public static final String P_REEVALUATE_ELITES = "reevaluate-elites"; public static final String P_SEQUENTIAL_BREEDING = "sequential"; public static final String P_CLONE_PIPELINE_AND_POPULATION = "clone-pipeline-and-population"; /** An array[subpop] of the number of elites to keep for that subpopulation */ public int[] elite; public double[] eliteFrac; public boolean[] reevaluateElites; public boolean sequentialBreeding; public boolean clonePipelineAndPopulation; public Population backupPopulation = null; public static final int NOT_SET = -1; public ThreadPool pool = new ThreadPool(); public boolean usingElitism(int subpopulation) { return (elite[subpopulation] > 0 ) || (eliteFrac[subpopulation] > 0); } public int numElites(EvolutionState state, int subpopulation) { if (elite[subpopulation] != NOT_SET) { return elite[subpopulation]; } else if (eliteFrac[subpopulation] == 0) { return 0; // no elites } else if (eliteFrac[subpopulation] != NOT_SET) { return (int) Math.max(Math.floor(state.population.subpops[subpopulation].individuals.length * eliteFrac[subpopulation]), 1.0); // AT LEAST 1 ELITE } else { state.output.warnOnce("Elitism error (SimpleBreeder). This shouldn't be able to happen. Please report."); return 0; // this shouldn't happen } } public void setup(final EvolutionState state, final Parameter base) { Parameter p = new Parameter(Initializer.P_POP).push(Population.P_SIZE); int size = state.parameters.getInt(p,null,1); // if size is wrong, we'll let Population complain about it -- for us, we'll just make 0-sized arrays and drop out. eliteFrac = new double[size]; elite = new int[size]; for(int i = 0; i < size; i++) eliteFrac[i] = elite[i] = NOT_SET; reevaluateElites = new boolean[size]; sequentialBreeding = state.parameters.getBoolean(base.push(P_SEQUENTIAL_BREEDING), null, false); if (sequentialBreeding && (size == 1)) // uh oh, this can't be right state.output.fatal("The Breeder is breeding sequentially, but you have only one population.", base.push(P_SEQUENTIAL_BREEDING)); clonePipelineAndPopulation =state.parameters.getBoolean(base.push(P_CLONE_PIPELINE_AND_POPULATION), null, true); if (!clonePipelineAndPopulation && (state.breedthreads > 1)) // uh oh, this can't be right state.output.fatal("The Breeder is not cloning its pipeline and population, but you have more than one thread.", base.push(P_CLONE_PIPELINE_AND_POPULATION)); int defaultSubpop = state.parameters.getInt(new Parameter(Initializer.P_POP).push(Population.P_DEFAULT_SUBPOP), null, 0); for(int x=0;x= 0", base.push(P_ELITE).push(""+x)); } } else if (state.parameters.exists(base.push(P_ELITE_FRAC).push(""+x),null)) { eliteFrac[x] = state.parameters.getDoubleWithMax(base.push(P_ELITE_FRAC).push(""+x),null,0.0, 1.0); if (eliteFrac[x] < 0.0) state.output.error("Elite Fraction of subpopulation " + x + " must be a real value between 0.0 and 1.0 inclusive", base.push(P_ELITE_FRAC).push(""+x)); } else if (defaultSubpop >= 0) { if (state.parameters.exists(base.push(P_ELITE).push(""+defaultSubpop),null)) { elite[x] = state.parameters.getIntWithDefault(base.push(P_ELITE).push(""+defaultSubpop),null,0); if (elite[x] < 0) state.output.warning("Invalid default subpopulation elite value."); // we'll fail later } else if (state.parameters.exists(base.push(P_ELITE_FRAC).push(""+defaultSubpop),null)) { eliteFrac[x] = state.parameters.getDoubleWithMax(base.push(P_ELITE_FRAC).push(""+defaultSubpop),null,0.0, 1.0); if (eliteFrac[x] < 0.0) state.output.warning("Invalid default subpopulation elite-frac value."); // we'll fail later } else // elitism is 0 { elite[x] = 0; } } else // elitism is 0 { elite[x] = 0; } // get reevaluation if (defaultSubpop >= 0 && !state.parameters.exists(base.push(P_REEVALUATE_ELITES).push(""+x),null)) { reevaluateElites[x] = state.parameters.getBoolean(base.push(P_REEVALUATE_ELITES).push(""+defaultSubpop), null, false); if (reevaluateElites[x]) state.output.warning("Elite reevaluation not specified for subpopulation " + x + ". Using values for default subpopulation " + defaultSubpop + ": " + reevaluateElites[x]); } else { reevaluateElites[x] = state.parameters.getBoolean(base.push(P_REEVALUATE_ELITES).push(""+x), null, false); } } state.output.exitIfErrors(); } /** Elites are often stored in the top part of the subpopulation; this function returns what part of the subpopulation contains individuals to replace with newly-bred ones (up to but not including the elites). */ public int computeSubpopulationLength(EvolutionState state, Population newpop, int subpopulation, int threadnum) { if (!shouldBreedSubpop(state, subpopulation, threadnum)) return newpop.subpops[subpopulation].individuals.length; // we're not breeding the population, just copy over the whole thing return newpop.subpops[subpopulation].individuals.length - numElites(state, subpopulation); // we're breeding population, so elitism may have happened } /** A simple breeder that doesn't attempt to do any cross- population breeding. Basically it applies pipelines, one per thread, to various subchunks of a new population. */ public Population breedPopulation(EvolutionState state) { Population newpop = null; if (clonePipelineAndPopulation) newpop = (Population) state.population.emptyClone(); else { if (backupPopulation == null) backupPopulation = (Population) state.population.emptyClone(); newpop = backupPopulation; newpop.clear(); backupPopulation = state.population; // swap in } // load elites into top of newpop loadElites(state, newpop); // how many threads do we really need? No more than the maximum number of individuals in any subpopulation int numThreads = 0; for(int x = 0; x < state.population.subpops.length; x++) numThreads = Math.max(numThreads, state.population.subpops[x].individuals.length); numThreads = Math.min(numThreads, state.breedthreads); if (numThreads < state.breedthreads) state.output.warnOnce("Largest subpopulation size (" + numThreads +") is smaller than number of breedthreads (" + state.breedthreads + "), so fewer breedthreads will be created."); int numinds[][] = new int[numThreads][state.population.subpops.length]; int from[][] = new int[numThreads][state.population.subpops.length]; for(int x=0;x 0) { numinds[y][x] = individualsPerThread + 1; slop--; } else numinds[y][x] = individualsPerThread; if (numinds[y][x] == 0) { state.output.warnOnce("More threads exist than can be used to breed some subpopulations (first example: subpopulation " + x + ")"); } from[y][x] = currentFrom; currentFrom += numinds[y][x]; } } /* for(int y=0;yupperbound) // uh oh! Someone blew it! state.output.fatal("Whoa! A breeding pipeline overwrote the space of another pipeline in subpopulation " + subpop + ". You need to check your breeding pipeline code (in produce() )."); bp.finishProducing(state,subpop,threadnum); } } } static class EliteComparator implements SortComparatorL { Individual[] inds; public EliteComparator(Individual[] inds) {super(); this.inds = inds;} public boolean lt(long a, long b) { return inds[(int)b].fitness.betterThan(inds[(int)a].fitness); } public boolean gt(long a, long b) { return inds[(int)a].fitness.betterThan(inds[(int)b].fitness); } } protected void unmarkElitesEvaluated(EvolutionState state, Population newpop) { for(int sub=0;substate.population.subpops[x].individuals.length) state.output.error("The number of elites for subpopulation " + x + " exceeds the actual size of the subpopulation", new Parameter(EvolutionState.P_BREEDER).push(P_ELITE).push(""+x)); if (numElites(state, x)==state.population.subpops[x].individuals.length) state.output.warning("The number of elites for subpopulation " + x + " is the actual size of the subpopulation", new Parameter(EvolutionState.P_BREEDER).push(P_ELITE).push(""+x)); } state.output.exitIfErrors(); // we assume that we're only grabbing a small number (say <10%), so // it's not being done multithreaded for(int sub=0;sub0) // we'll need to sort { int[] orderedPop = new int[state.population.subpops[sub].individuals.length]; for(int x=0;x

Ads help maintain this website.