/* Copyright 2006 by Sean Luke Licensed under the Academic Free License version 3.0 See the file "LICENSE" for more information */ package ec.gp; import ec.*; import ec.util.*; /* * GPNodeBuilder.java * * Created: Thu Oct 7 17:31:41 1999 * By: Sean Luke */ /** * GPNodeBuilder is a Prototype which defines the superclass for objects * which create ("grow") GP trees, whether for population initialization, * subtree mutation, or whatnot. It defines a single abstract method, * newRootedTree(...), which must be implemented to grow the tree. * *
GPNodeBuilder also provides some facilities for user-specification * of probabilities of various tree sizes, which the tree builder can use * as it sees fit (or totally ignore). * There are two such facilities. First, the user might * specify a minimum and maximum range for tree sizes to be picked from; * trees would likely be picked uniformly from this range. Second, the * user might specify an array, num-sizes long, of probabilities of * tree sizes, in order to give a precise probability distribution.
Parameters
base.min-size int >= 1, or undefined |
(smallest valid size, see discussion above) |
base.max-size int >= min-size, or undefined |
(largest valid size, see discussion above) |
base.num-sizes int >= 1, or underfined |
(number of sizes in the size distribution, see discussion above) |
base.size.n 0.0 <= float <= 1.0, or undefined |
(probability of choosing size n. See discussion above) |
requestedSize is an
optional argument which differs based on the GPNodeBuilder used.
Typically it is set to a tree size that the calling method wants
the GPNodeBuilder to produce; the GPNodeBuilder is not obligated to
produce a tree of this size, but it should attempt to interpret this
argument as appropriate for the given algorithm. To indicate that
you don't care what size the tree should be, you can pass NOSIZEGIVEN.
However if the algorithm requires you to provide a size, it
will generate a fatal error to let you know. */
public static final int NOSIZEGIVEN = -1;
public static final int CHECK_BOUNDARY = 8;
public static final String P_MINSIZE = "min-size";
public static final String P_MAXSIZE = "max-size";
public static final String P_NUMSIZES = "num-sizes";
public static final String P_SIZE = "size";
public int minSize; /** the minium possible size -- if unused, it's 0 */
public int maxSize; /** the maximum possible size -- if unused, it's 0 */
public float[] sizeDistribution; /* sizeDistribution[x] represents
the likelihood of size x appearing
-- if unused, it's null */
/** Returns true if some size distribution (either minSize and maxSize,
or sizeDistribution) is set up by the user in order to pick sizes randomly. */
public boolean canPick()
{
return (minSize!=0 || sizeDistribution !=null);
}
/** Assuming that either minSize and maxSize, or sizeDistribution, is defined,
picks a random size from minSize...maxSize inclusive, or randomly
from sizeDistribution. */
public int pickSize(final EvolutionState state, final int thread)
{
if (minSize>0)
{
// pick from minSize...maxSize
return state.random[thread].nextInt(maxSize-minSize+1) + minSize;
}
else if (sizeDistribution!=null)
{
// pick from distribution
return RandomChoice.pickFromDistribution(
sizeDistribution,
state.random[thread].nextFloat()) + 1 ;
}
else throw new InternalError("Neither minSize nor sizeDistribution is defined in GPNodeBuilder");
}
public Object clone()
{
try
{
GPNodeBuilder c = (GPNodeBuilder)(super.clone());
if (sizeDistribution != null) c.sizeDistribution =
(float[]) (sizeDistribution.clone());
return c;
}
catch (CloneNotSupportedException e)
{ throw new InternalError(); } // never happens
}
public void setup(final EvolutionState state, final Parameter base)
{
Parameter def = defaultBase();
// min and max size
if (state.parameters.exists(base.push(P_MINSIZE),
def.push(P_MINSIZE)))
{
if (!(state.parameters.exists(base.push(P_MAXSIZE),
def.push(P_MAXSIZE))))
state.output.fatal("This GPNodeBuilder has a " +
P_MINSIZE + " but not a " + P_MAXSIZE + ".");
minSize = state.parameters.getInt(
base.push(P_MINSIZE), def.push(P_MINSIZE),1);
if (minSize==0)
state.output.fatal("The GPNodeBuilder must have a min size >= 1.",
base.push(P_MINSIZE), def.push(P_MINSIZE));
maxSize = state.parameters.getInt(
base.push(P_MAXSIZE), def.push(P_MAXSIZE),1);
if (maxSize==0)
state.output.fatal("The GPNodeBuilder must have a max size >= 1.",
base.push(P_MAXSIZE), def.push(P_MAXSIZE));
if (minSize > maxSize)
state.output.fatal(
"The GPNodeBuilder must have min size <= max size.",
base.push(P_MINSIZE), def.push(P_MINSIZE));
}
else if (state.parameters.exists(base.push(P_MAXSIZE),
def.push(P_MAXSIZE)))
state.output.fatal("This GPNodeBuilder has a " +
P_MAXSIZE + " but not a " + P_MINSIZE + ".",
base.push(P_MAXSIZE), def.push(P_MAXSIZE));
// load sizeDistribution
else if (state.parameters.exists(base.push(P_NUMSIZES),
def.push(P_NUMSIZES)))
{
int siz = state.parameters.getInt(
base.push(P_NUMSIZES), def.push(P_NUMSIZES),1);
if (siz==0)
state.output.fatal("The number of sizes in the GPNodeBuilder's distribution must be >= 1. ");
sizeDistribution = new float[siz];
if (state.parameters.exists(base.push(P_SIZE).push("0"),
def.push(P_SIZE).push("0")))
state.output.warning(
"GPNodeBuilder does not use size #0 in the distribution",
base.push(P_SIZE).push("0"),
def.push(P_SIZE).push("0"));
float sum = 0.0f;
for(int x=0;x