/*
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.