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


package ec.es;
import ec.*;
import ec.util.*;

/* 
 * MuCommaLambdaBreeder.java
 * 
 * Created: Thu Sep  7 17:27:47 2000
 * By: Sean Luke
 */

/**
 * MuCommaLambdaBreeder is a Breeder which, together with
 * ESSelection, implements the (mu,lambda) breeding strategy and gathers
 * the comparison data you can use to implement a 1/5-rule mutation mechanism.
 * 
 * 

Evolution strategies breeders require a "mu" parameter and a "lambda" * parameter for each subpopulation. "mu" refers to the number of parents * from which the new population will be built. "lambda" refers to the * number of children generated by the mu parents. Subpopulation sizes * will change as necessary to accommodate this fact in later generations. * The only rule for initial subpopulation sizes is that they must be * greater than or equal to the mu parameter for that subpopulation. * *

You can now set your initial subpopulation * size to whatever you like, totally independent of lambda and mu, * as long as it is >= mu. * *

MuCommaLambdaBreeder stores mu and lambda values for each subpopulation * in the population, as well as comparisons. A comparison tells you * if >1/5, <1/5 or =1/5 of the new population was better than its * parents (the so-called evolution strategies "one-fifth rule". * Although the comparisons are gathered, no mutation objects are provided * which actually use them -- you're free to use them in any mutation * objects you care to devise which requires them. * *

To do evolution strategies evolution, the * breeding pipelines should contain at least one ESSelection selection method. * While a child is being generated by the pipeline, the ESSelection object will return a parent * from the pool of mu parents. The particular parent is chosen round-robin, so all the parents * will have an equal number of children. It's perfectly fine to have more than one ESSelection * object in the tree, or to call the same one repeatedly during the course of generating a child; * all such objects will consistently return the same parent. They only increment to the next * parent in the pool of mu parents after the child has been created from the pipeline. You can * also mix ESSelection operators with other operators (like Tournament Selection). But you ought * to have at least one ESSelection operator in the pipeline -- else it wouldn't be Evolution * Strategies, would it?

Parameters

es.lambda.subpop-num
int >= 0
Specifies the 'lambda' parameter for the subpopulation.
es.mu.subpop-num
int: a multiple of "lambda"
Specifies the 'mu' parameter for the subpopulation.
* @author Sean Luke * @version 1.0 */ public class MuCommaLambdaBreeder extends Breeder { public static final String P_MU = "mu"; public static final String P_MU_FRACTION = "mu-fraction"; public static final String P_LAMBDA = "lambda"; public int[] mu; public int[] lambda; public Population parentPopulation; public byte[] comparison; public static final byte C_OVER_ONE_FIFTH_BETTER = 1; public static final byte C_UNDER_ONE_FIFTH_BETTER = -1; public static final byte C_EXACTLY_ONE_FIFTH_BETTER = 0; /** Modified by multiple threads, don't fool with this */ public int[] count; /** lambda should be no SMALLER than mu times this value. This varies between (mu,lambda) (where it's 2) and (mu + lambda) (where it's 1). */ public int maximumMuLambdaDivisor() { return 2; } public void setup(final EvolutionState state, final Parameter base) { // we're not using the 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. mu = new int[size]; lambda = new int[size]; comparison = new byte[size]; // load mu and lambda data for(int x=0;x= 1",ESDefaults.base().push(P_LAMBDA).push(""+x)); } else { state.output.warning("lambda not specified for subpopulation " + x + ", setting it to the subopulation size, that is, " + ppval + ".", ESDefaults.base().push(P_LAMBDA).push(""+x),null); lambda[x] = ppval; if (lambda[x] == 0) state.output.error("Subpouplation Size must be >= 1", pp, null); } if (state.parameters.exists(ESDefaults.base().push(P_MU).push(""+x),null)) // we defined mu { // did we also define a mu-fraction? if (state.parameters.exists(ESDefaults.base().push(P_MU_FRACTION).push(""+x), null)) state.output.warning("Defined both a mu and mu-fraction for subpopulation " + x + ". Only mu will be used. ", ESDefaults.base().push(P_MU).push(""+x), ESDefaults.base().push(P_MU_FRACTION).push(""+x)); mu[x] = state.parameters.getInt(ESDefaults.base().push(P_MU).push(""+x),null,1); if (mu[x]==0) state.output.error("mu must be an integer >= 1",ESDefaults.base().push(P_MU).push(""+x), null); else if (lambda[x] % mu[x] != 0) { if (mu[x] > lambda[x] / maximumMuLambdaDivisor()) { state.output.warning("mu (" + mu[x] + ") for subpopulation " + x + " is greater than lambda (" + lambda[x] + ") / " + maximumMuLambdaDivisor() + ". Mu will be set to half of lambda, that is, " + lambda[x] / maximumMuLambdaDivisor() + "."); mu[x] = lambda[x] / maximumMuLambdaDivisor(); } if (lambda[x] % mu[x] != 0) // check again state.output.error("mu must be a divisor of lambda", ESDefaults.base().push(P_MU).push(""+x)); } else if (mu[x] > ppval) { state.output.warning("mu is presently > the initial subpopulation size. Mu will be set to the subpopulation size, that is, " + ppval + ".", ESDefaults.base().push(P_MU).push(""+x), null); mu[x] = ppval; } } else if (state.parameters.exists(ESDefaults.base().push(P_MU_FRACTION).push(""+x), null)) // we defined mu in terms of a fraction { double mufrac = state.parameters.getDoubleWithMax(ESDefaults.base().push(P_MU_FRACTION).push(""+x), null, 0.0, 1.0 / maximumMuLambdaDivisor()); if (mufrac < 0.0) state.output.fatal("Mu-Fraction must be a value between 0.0 and " + 1.0 / maximumMuLambdaDivisor(), ESDefaults.base().push(P_MU_FRACTION).push(""+x), null); int m = (int)Math.max(lambda[x] * mufrac, 1.0); mu[x] = m; // find the largest divisor of lambda[x] which is <= m. This is ugly double val = lambda[x] / (double) mu[x]; while (val != (int) val) { mu[x]--; val = lambda[x] / (double) mu[x]; } state.output.message("Mu-Fraction " + mufrac + " yields a mu of " + m + ", adjusted to " + mu[x]); } else state.output.fatal("Neither a Mu or a Mu-Fraction was provided for subpopulation " + x, ESDefaults.base().push(P_MU).push(""+x), ESDefaults.base().push(P_MU_FRACTION).push(""+x)); } state.output.exitIfErrors(); } /** Sets all subpopulations in pop to the expected lambda size. Does not fill new slots with individuals. */ public Population setToLambda(Population pop, EvolutionState state) { for(int x=0;x lambda[x] / 5.0) // note double division comparison[x] = C_OVER_ONE_FIFTH_BETTER; else if (numChildrenBetter < lambda[x] / 5.0) // note double division comparison[x] = C_UNDER_ONE_FIFTH_BETTER; else comparison[x] = C_EXACTLY_ONE_FIFTH_BETTER; } } // load the parent population parentPopulation = state.population; // MU COMPUTATION // At this point we need to do load our population info // and make sure it jibes with our mu info // the first issue is: is the number of subpopulations // equal to the number of mu's? if (mu.length!=state.population.subpops.length) // uh oh state.output.fatal("For some reason the number of subpops is different than was specified in the file (conflicting with Mu and Lambda storage).",null); // next, load our population, make sure there are no subpopulations smaller than the mu's 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;y

Ads help maintain this website.