/* 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 java.io.*; import ec.util.*; import ec.EvolutionState; /* * GPNode.java * * Created: Fri Aug 27 17:14:12 1999 * By: Sean Luke */ /** * GPNode is a GPNodeParent which is the abstract superclass of * all GP function nodes in trees. GPNode contains quite a few functions * for cloning subtrees in special ways, counting the number of nodes * in subtrees in special ways, and finding specific nodes in subtrees. * * GPNode's lightClone() method does not clone its children (it copies the * array, but that's it). If you want to deep-clone a tree or subtree, you * should use one of the cloneReplacing(...) methods instead. * *
GPNodes contain a number of important items: *
In addition to serialization for checkpointing, GPNodes may read and write themselves to streams in three ways. * *
Parameters
base.nc String |
(name of the node constraints for the GPNode) |
Default Base
gp.node
*
* @author Sean Luke
* @version 1.0
*/
public abstract class GPNode implements GPNodeParent, Prototype
{
public static final String P_NODE = "node";
public static final String P_NODECONSTRAINTS = "nc";
public static final String GPNODEPRINTTAB = " ";
public static final int MAXPRINTBYTES = 40;
public static final int NODESEARCH_ALL = 0;
public static final int NODESEARCH_TERMINALS = 1;
public static final int NODESEARCH_NONTERMINALS = 2;
public static final int NODESEARCH_CUSTOM = 3;
public static final int SITUATION_NEWIND = 0;
public static final int SITUATION_MUTATION = 1;
// beats me if Java compilers will take advantage of the int->byte shortening.
// They may want everything aligned, in which case they may buffer the object
// anyway, hope not!
/** The GPNode's parent. 4 bytes. :-( But it really helps simplify breeding. */
public GPNodeParent parent;
public GPNode children[];
/** The argument position of the child in its parent.
This is a byte to save space (GPNode is the critical object space-wise) --
besides, how often do you have 256 children? You can change this to a short
or int easily if you absolutely need to. It's possible to eliminate even
this and have the child find itself in its parent, but that's an O(children[])
operation, and probably not inlinable, so I figure a byte is okay. */
public byte argposition;
/** The GPNode's constraints. This is a byte to save space -- how often do
you have 256 different GPNodeConstraints? Well, I guess it's not infeasible.
You can increase this to an int without much trouble. You typically
shouldn't access the constraints through this variable -- use the constraints(state)
method instead. */
public byte constraints;
/* Returns the GPNode's constraints. A good JIT compiler should inline this. */
public final GPNodeConstraints constraints(final GPInitializer initializer)
{
return initializer.nodeConstraints[constraints];
}
/** The default base for GPNodes -- defined even though
GPNode is abstract so you don't have to in subclasses. */
public Parameter defaultBase()
{
return GPDefaults.base().push(P_NODE);
}
/** You ought to override this method to check to make sure that the
constraints are valid as best you can tell. Things you might
check for:
About input: input is special; it is how data is passed between parent and child nodes. If children "receive" data from their parent node when it evaluates them, they should receive this data stored in input. If (more likely) the parent "receives" results from its children, it should pass them an input object, which they'll fill out, then it should check this object for the returned value.
A tree is typically evaluated by dropping a GPData into the root. When the root returns, the resultant input should hold the return value.
In general, you should not be creating new GPDatas. If you think about it, in most conditions (excepting ADFs and ADMs) you can use and reuse input for most communications purposes between parents and children.
So, let's say that your GPNode function implements the boolean AND function,
and expects its children to return return boolean values (as it does itself).
You've implemented your GPData subclass to be, uh, BooleanData, which
looks like
* public class BooleanData extends GPData
* {
* public boolean result;
* public GPData copyTo(GPData gpd)
* {
* ((BooleanData)gpd).result = result;
* }
* }
...so, you might implement your eval(...) function as follows:
* public void eval(final EvolutionState state,
* final int thread,
* final GPData input,
* final ADFStack stack,
* final GPIndividual individual,
* final Problem problem
* {
* BooleanData dat = (BooleanData)input;
* boolean x;
*
* // evaluate the first child
* children[0].eval(state,thread,input,stack,individual,problem);
*
* // store away its result
* x = dat.result;
*
* // evaluate the second child
* children[1].eval(state,thread,input,stack,individual,problem);
*
* // return (in input) the result of the two ANDed
*
* dat.result = dat.result && x;
* return;
* }
*/
public abstract void eval(final EvolutionState state,
final int thread,
final GPData input,
final ADFStack stack,
final GPIndividual individual,
final Problem problem);
}