/*
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.*;
/*
* ADFStack.java
*
* Created: Mon Oct 25 19:48:12 1999
* By: Sean Luke
*/
/**
* ADFStack is a special data object used to hold ADF data.
* This object is a weird beast and takes some explaining.
* It consists of a main stack, a secondary "substack", and a "reserve" area
* (also implemented as a stack,
* but it doesn't have to be). The reserve is used to "recycle" objects
* rather than having to create then new every time.
*
*
When an ADF is evaluated, it first
* evaluates its children, then it calls push() on the ADFstack.
* push() either creates a new ADFContext, or it fetches one from the
* reserve if possible. It then pushes the context on the main stack,
* and also returns the context. The ADF fills the context's arguments
* with the results of its childrens' evaluation, and sets numargs to
* the number of
* arguments, then evaluates the
* ADF's associated function tree,
*
*
When an ADM is evaluated, it calls push() on the ADFstack.
* The ADM then fills the context's adm node with itself, and sets numargs
* to the number of children it has. Then it calls the ADM's associated
* function tree.
*
*
In that tree, if an argument terminal of value n is evaluated,
* the argument terminal calls evaluate(...) on the top context
* on the ADF stack and returns the result.
* This method does different things depending on whether the top context
* represented an ADF or an ADM. If it was an ADF, the context simply sets
* input to the value of argument n in the context's argument list,
* and returns input. If it was an ADM, the context pops itself off the
* stack and pushes itself on the substack (to set up the right context
* for evaluating an original child of the ADM), then evaluates child n
* of the ADM, then pops itself off the substack and pushes itself back
* on the stack to restore the context. Input is set to the evaluated
* results, and input is returned.
*
Parameters
base.context
classname, inherits and != ec.gp.GPContext |
(the stack's GPContext class) |
Parameters
gp.adf-stack
Parameter bases
base.context
| (context_proto) |
* @author Sean Luke
* @version 1.0
*/
public class ADFStack implements Prototype
{
public static final String P_ADFSTACK = "adf-stack";
public static final String P_ADF = "adf";
public static final String P_CONTEXT = "context";
public ADFContext context_proto;
public static final int INITIAL_STACK_SIZE = 2; // seems like a good size
protected int onStack;
protected int onSubstack;
protected int inReserve;
protected ADFContext[] stack;
protected ADFContext[] substack;
protected ADFContext[] reserve;
public ADFStack()
{
stack = new ADFContext[INITIAL_STACK_SIZE];
substack = new ADFContext[INITIAL_STACK_SIZE];
reserve = new ADFContext[INITIAL_STACK_SIZE];
onStack=0;
onSubstack = 0;
inReserve = 0;
}
public Parameter defaultBase()
{
return GPDefaults.base().push(P_ADFSTACK);
}
public void setup(final EvolutionState state, final Parameter base)
{
// load our prototype
Parameter p = base.push(P_CONTEXT);
Parameter d = defaultBase().push(P_CONTEXT);
context_proto = (ADFContext)
(state.parameters.getInstanceForParameterEq(p,d,ADFContext.class));
context_proto.setup(state,p);
}
public Object clone()
{
try
{
ADFStack myobj = (ADFStack) (super.clone());
// deep-cloned stuff
myobj.context_proto = (ADFContext)(context_proto.clone());
// clone the stack arrays -- dunno if this is faster than new ADFContext[...]
myobj.stack = (ADFContext[])(stack.clone());
myobj.substack = (ADFContext[])(substack.clone());
myobj.reserve = (ADFContext[])(reserve.clone());
// fill 'em up
for(int x=0;x0) obj = reserve[--inReserve];
else obj = (ADFContext)(context_proto.clone()); // hopefully that doesn't have to happen too many times
return obj;
}
/** Pushes an ADFContext onto the main stack. The best way to get an
ADFContext to push onto the stack is with get(). Returns obj. */
public final ADFContext push(ADFContext obj)
{
// Double stack if necessary
if (onStack==stack.length)
{
ADFContext[] newstack = new ADFContext[stack.length * 2];
System.arraycopy(stack,0,newstack,0,stack.length);
stack = newstack;
}
// Add to stack
stack[onStack++] = obj;
// return it
return obj;
}
/** Pops off n items from the stack, if possible. Returns
the number of items actually popped off. */
public final int pop(int n)
{
int x;
for(x = 0 ; x < n; x++)
{
// Anything left on the stack?
if (onStack==0) break;
// Remove one from stack
ADFContext obj = stack[--onStack];
// Double reserve if necessary
if (inReserve==reserve.length)
{
ADFContext[] newreserve = new ADFContext[reserve.length * 2];
System.arraycopy(reserve,0,newreserve,0,reserve.length);
reserve = newreserve;
}
// Add to reserve
reserve[inReserve++] = obj;
}
return x;
}
/** Returns the nth item in the stack (0-indexed), or null if
this goes to the bottom of the stack. */
public final ADFContext top(int n)
{
// is this beyond the stack?
if (onStack-n <= 0) return null;
else return stack[onStack-n-1];
}
/** Moves n items onto the substack (pops them off the stack and pushes them onto the substack). Returns the actual number of items for which this was done. */
public final int moveOntoSubstack(int n)
{
int x;
for(x=0;xn items onto the stack (popss them off the substack and pushes them onto the stack). Returns the actual number of items moved from the Substack onto the main stack */
public final int moveFromSubstack(int n)
{
int x;
for(x=0;x0) moveFromSubstack(onSubstack);
if (onStack>0) pop(onStack);
}
}