Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPNode.java @ 12147

Last change on this file since 12147 was 6152, checked in by bfarka, 14 years ago

added ecj and custom statistics to communicate with the okb services #1441

File size: 57.6 KB
Line 
1/*
2  Copyright 2006 by Sean Luke
3  Licensed under the Academic Free License version 3.0
4  See the file "LICENSE" for more information
5*/
6
7
8package ec.gp;
9import ec.*;
10import java.io.*;
11import ec.util.*;
12import ec.EvolutionState;
13
14/*
15 * GPNode.java
16 *
17 * Created: Fri Aug 27 17:14:12 1999
18 * By: Sean Luke
19 */
20
21/**
22 * GPNode is a GPNodeParent which is the abstract superclass of
23 * all GP function nodes in trees.  GPNode contains quite a few functions
24 * for cloning subtrees in special ways, counting the number of nodes
25 * in subtrees in special ways, and finding specific nodes in subtrees.
26 *
27 * GPNode's lightClone() method does not clone its children (it copies the
28 * array, but that's it).  If you want to deep-clone a tree or subtree, you
29 * should use one of the cloneReplacing(...) methods instead.
30 *
31 * <p>GPNodes contain a number of important items:
32 * <ul><li>A <i>constraints</i> object which defines the name of the node,
33 * its arity, and its type constraints. This
34 * object is shared with all GPNodes of the same function name/arity/returntype/childtypes.
35 * <li>A <i>parent</i>.  This is either another GPNode, or (if this node
36 * is the root) a GPTree.
37 * <li>Zero or more <i>children</i>, which are GPNodes.
38 * <li>An argument position in its parent.
39 * </ul>
40 *
41
42 * <p>In addition to serialization for checkpointing, GPNodes may read and write themselves to streams in three ways.
43 *
44 * <ul>
45 * <li><b>writeNode(...,DataOutput)/readNode(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
46 * transmits or receives a GPNode in binary.  It is the most efficient approach to sending
47 * GPNodes over networks, etc.  The default versions of writeNode/readNode both generate errors.
48 * GPNode subclasses should override them to provide more functionality, particularly if you're planning on using
49 * ECJ in a distributed fashion.  Both of these functions are called by GPNode's readRootedTree/writeRootedTree
50 * respectively, which handle the reading/printing of the trees as a whole.
51 *
52 * <li><b>printNode(...,PrintWriter)/readNode(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
53 * approach transmits or receives a GPNode in text encoded such that the GPNode is largely readable
54 * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will typically encode numbers
55 * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
56 * files for inspection, slight modification, then reading back in later on.  Both of these functions are called by GPNode's readRootedTree/writeRootedTree
57 * respectively, which handle the reading/printing of the trees as a whole.  Notably readRootedNode
58 * will try to determine what kind of node is next, then call <b>readNode</b> on the prototype for that
59 * node to generate the node.  <b>printNode</b> by default calls toString() and
60 * prints the result, though subclasses often override this to provide additional functionality (notably
61 * ERCs).
62 *
63 * <li><b>printNodeForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
64 * approach prints a GPNode in a fashion intended for human consumption only.
65 * <b>printNodeForHumans</b> by default calls toStringForHumans() (which by default calls toString()) and
66 * prints the result.  printNodeForHumans is called by <b>printRootedTreeForHumans</b>, which handles
67 * printing of the entire GPNode tree.
68 * </ul>
69
70
71 <p><b>Parameters</b><br>
72 <table>
73 <tr><td valign=top><i>base</i>.<tt>nc</tt><br>
74 <font size=-1>String</font></td>
75 <td valign=top>(name of the node constraints for the GPNode)</td></tr>
76 </table>
77
78 <p><b>Default Base</b><br>
79 gp.node
80
81 *
82 * @author Sean Luke
83 * @version 1.0
84 */
85
86public abstract class GPNode implements GPNodeParent, Prototype
87    {
88    public static final String P_NODE = "node";
89    public static final String P_NODECONSTRAINTS = "nc";
90    public static final String GPNODEPRINTTAB = "    ";
91    public static final int MAXPRINTBYTES = 40;
92
93    public static final int NODESEARCH_ALL = 0;
94    public static final int NODESEARCH_TERMINALS = 1;
95    public static final int NODESEARCH_NONTERMINALS = 2;
96    public static final int NODESEARCH_CUSTOM = 3;
97
98    public static final int SITUATION_NEWIND = 0;
99    public static final int SITUATION_MUTATION = 1;
100   
101    // beats me if Java compilers will take advantage of the int->byte shortening.
102    // They may want everything aligned, in which case they may buffer the object
103    // anyway, hope not!
104
105    /** The GPNode's parent.  4 bytes.  :-(  But it really helps simplify breeding. */
106    public GPNodeParent parent;
107    public GPNode children[];
108    /** The argument position of the child in its parent.
109        This is a byte to save space (GPNode is the critical object space-wise) --
110        besides, how often do you have 256 children? You can change this to a short
111        or int easily if you absolutely need to.  It's possible to eliminate even
112        this and have the child find itself in its parent, but that's an O(children[])
113        operation, and probably not inlinable, so I figure a byte is okay. */
114    public byte argposition;
115    /** The GPNode's constraints.  This is a byte to save space -- how often do
116        you have 256 different GPNodeConstraints?  Well, I guess it's not infeasible.
117        You can increase this to an int without much trouble.  You typically
118        shouldn't access the constraints through this variable -- use the constraints(state)
119        method instead. */
120    public byte constraints;
121
122    /* Returns the GPNode's constraints.  A good JIT compiler should inline this. */
123    public final GPNodeConstraints constraints(final GPInitializer initializer)
124        {
125        return initializer.nodeConstraints[constraints];
126        }
127
128    /** The default base for GPNodes -- defined even though
129        GPNode is abstract so you don't have to in subclasses. */
130    public Parameter defaultBase()
131        {
132        return GPDefaults.base().push(P_NODE);
133        }
134
135    /** You ought to override this method to check to make sure that the
136        constraints are valid as best you can tell.  Things you might
137        check for:
138
139        <ul>
140        <li> children.length is correct
141        <li> certain arguments in constraints.childtypes are
142        swap-compatible with each other
143        <li> constraints.returntype is swap-compatible with appropriate
144        arguments in constraints.childtypes
145        </ul>
146       
147        You can't check for everything, of course, but you might try some
148        obvious checks for blunders.  The default version of this method
149        is empty for now, but you should still call super.checkConstraints(state)
150        just to be certain.
151
152        The ultimate caller of this method must guarantee that he will eventually
153        call state.output.exitIfErrors(), so you can freely use state.output.error
154        instead of state.output.fatal(), which will help a lot.
155       
156        Warning: this method may get called more than once.
157    */
158
159    public void checkConstraints(final EvolutionState state,
160        final int tree,
161        final GPIndividual typicalIndividual,
162        final Parameter individualBase)
163        { }
164
165    /**
166        Sets up a <i>prototypical</i> GPNode with those features all nodes of that
167        prototype share, and nothing more.  So no filled-in children,
168        no argposition, no parent.  Yet.
169
170        This must be called <i>after</i> the GPTypes and GPNodeConstraints
171        have been set up.  Presently they're set up in GPInitializer,
172        which gets called before this does, so we're safe.
173       
174        You should override this if you need to load some special features on
175        a per-function basis.  Note that base hangs off of a function set, so
176        this method may get called for different instances in the same GPNode
177        class if they're being set up as prototypes for different GPFunctionSets.
178
179        If you absolutely need some global base, then you should use something
180        hanging off of GPDefaults.base().
181
182        The ultimate caller of this method must guarantee that he will eventually
183        call state.output.exitIfErrors(), so you can freely use state.output.error
184        instead of state.output.fatal(), which will help a lot.
185    */
186
187    public void setup(final EvolutionState state, final Parameter base)
188        {
189        Parameter def = defaultBase();
190
191        // determine my constraints -- at this point, the constraints should have been loaded.
192        String s = state.parameters.getString(base.push(P_NODECONSTRAINTS),
193            def.push(P_NODECONSTRAINTS));
194        if (s==null)
195            state.output.fatal("No node constraints are defined for the GPNode " +
196                toStringForError(),base.push(P_NODECONSTRAINTS),
197                def.push(P_NODECONSTRAINTS));
198        else constraints = GPNodeConstraints.constraintsFor(s,state).constraintNumber;
199
200        // The number of children is determined by the constraints.  Though
201        // for some special versions of GPNode, we may have to enforce certain
202        // rules, checked in children versions of setup(...)
203
204        GPNodeConstraints constraintsObj = constraints(((GPInitializer)state.initializer));
205        int len = constraintsObj.childtypes.length;
206        if (len == 0) children = constraintsObj.zeroChildren;
207        else children = new GPNode[len];
208        }
209
210    /** Returns the argument type of the slot that I fit into in my parent. 
211        If I'm the root, returns the treetype of the GPTree. */
212    public final GPType parentType(final GPInitializer initializer)
213        {
214        if (parent instanceof GPNode)
215            return ((GPNode)parent).constraints(initializer).childtypes[argposition];
216        else // it's a tree root
217            return ((GPTree)parent).constraints(initializer).treetype;
218        }
219
220
221    /** Verification of validity of the node in the tree -- strictly for debugging purposes only */
222    final int verify(EvolutionState state, GPFunctionSet set, int index)
223        {
224        if (!(state.initializer instanceof GPInitializer))
225            { state.output.error("" + index + ": Initializer is not a GPInitializer"); return index+1; }
226           
227        GPInitializer initializer = (GPInitializer)(state.initializer);
228       
229        // 1. Is the parent and argposition right?
230        if (parent == null)
231            { state.output.error("" + index + ": null parent"); return index+1; }
232        if (argposition < 0)
233            { state.output.error("" + index + ": negative argposition"); return index+1; }
234        if (parent instanceof GPTree && ((GPTree)parent).child != this)
235            { state.output.error("" + index + ": I think I am a root node, but my GPTree does not think I am a root node"); return index+1; }
236        if (parent instanceof GPTree && argposition != 0)
237            { state.output.error("" + index + ": I think I am a root node, but my argposition is not 0"); return index+1; }
238        if (parent instanceof GPNode && argposition >= ((GPNode)parent).children.length)
239            { state.output.error("" + index + ": argposition outside range of parent's children array"); return index+1; }
240        if (parent instanceof GPNode && ((GPNode)parent).children[argposition] != this)
241            { state.output.error("" + index + ": I am not found in the provided argposition ("+argposition+") of my parent's children array"); return index+1; }
242
243        // 2. Are the parents and argpositions right for my kids? [need to double check]
244        if (children==null)
245            { state.output.error("" + index + ": Null Children Array"); return index+1; }
246        for(int x=0;x<children.length;x++)
247            {
248            if (children[x] == null)
249                { state.output.error("" + index + ": Null Child (#" + x + " )"); return index+1; }
250            if (children[x].parent != this)
251                { state.output.error("" + index + ": child #"+x+" does not have me as a parent"); return index+1; }
252            if (children[x].argposition < 0)
253                { state.output.error("" + index + ": child #"+x+" argposition is negative"); return index+1; }
254            if (children[x].argposition != x)
255                { state.output.error("" + index + ": child #"+x+" argposition does not match position in the children array"); return index+1; }
256            }
257       
258        // 3. Do I have valid constraints?
259        if (constraints < 0 || constraints >= initializer.numNodeConstraints)
260            { state.output.error("" + index + ": Preposterous node constraints (" + constraints + ")"); return index+1; }
261       
262        // 4. Am I swap-compatable with my parent?
263        if (parent instanceof GPNode && !constraints(initializer).returntype.compatibleWith(initializer,
264                ((GPNode)(parent)).constraints(initializer).childtypes[argposition]))
265            { state.output.error("" + index + ": Incompatable GP type between me and my parent"); return index+1; }
266        if (parent instanceof GPTree && !constraints(initializer).returntype.compatibleWith(initializer,
267                ((GPTree)(parent)).constraints(initializer).treetype))
268            { state.output.error("" + index + ": I am root, but incompatable GP type between me and my tree return type"); return index+1; }
269       
270        // 5. Is my class in the GPFunctionSet?
271        GPNode[] nodes = set.nodesByArity[constraints(initializer).returntype.type][children.length];
272        boolean there = false;
273        for(int x=0;x<nodes.length;x++)
274            if (nodes[x].getClass() == this.getClass()) { there = true; break; }
275        if (!there)
276            { state.output.error("" + index + ": I'm not in the function set."); return index+1; }
277           
278        // otherwise we've passed -- go to next node
279        index++;
280        for(int x=0;x<children.length;x++)
281            index = children[x].verify(state, set, index);
282        state.output.exitIfErrors();
283        return index;
284        }
285
286
287    /** Returns true if I can swap into node's position. */
288
289    public final boolean swapCompatibleWith(final GPInitializer initializer,
290        final GPNode node)
291        {
292        // I'm atomically compatible with him; a fast check
293        if (constraints(initializer).returntype==node.constraints(initializer).returntype)  // no need to check for compatibility
294            return true;
295
296        // I'm set compatible with his parent's swap-position
297        GPType type;
298        if (node.parent instanceof GPNode)  // it's a GPNode
299            type =
300                ((GPNode)(node.parent)).constraints(initializer).childtypes[node.argposition];
301        else // it's a tree root; I'm set compatible with the GPTree type
302            type =
303                ((GPTree)(node.parent)).constraints(initializer).treetype;
304       
305        return constraints(initializer).returntype.compatibleWith(initializer,type);
306        }
307
308    /** Returns the number of nodes, constrained by g.test(...)
309        in the subtree for which this GPNode is root.  This might
310        be sped up by caching the value.  O(n). */
311    public int numNodes(final GPNodeGatherer g)
312        {
313        int s=0;
314        for(int x=0;x<children.length;x++) s += children[x].numNodes(g);
315        return s + (g.test(this) ? 1 : 0);
316        }
317
318    /** Returns the number of nodes, constrained by nodesearch,
319        in the subtree for which this GPNode is root.
320        This might be sped up by cacheing the value somehow.  O(n). */
321    public int numNodes(final int nodesearch)
322        {
323        int s=0;
324        for(int x=0;x<children.length;x++) s += children[x].numNodes(nodesearch);
325        return s + ((nodesearch==NODESEARCH_ALL ||
326                (nodesearch==NODESEARCH_TERMINALS && children.length==0) ||
327                (nodesearch==NODESEARCH_NONTERMINALS && children.length>0)) ? 1 : 0);
328        }
329
330    /** Returns the depth of the tree, which is a value >= 1.  O(n). */
331    public int depth()
332        {
333        int d=0;
334        int newdepth;
335        for(int x=0;x<children.length;x++)
336            {
337            newdepth = children[x].depth();
338            if (newdepth>d) d = newdepth;
339            }
340        return d + 1;
341        }
342       
343    /** Returns the path length of the tree, which is the sum of all paths from all nodes to the root.   O(n). */
344    public int pathLength(int nodesearch) { return pathLength(NODESEARCH_ALL, 0); }
345   
346    int pathLength(int nodesearch, int currentDepth)
347        {
348        int sum = currentDepth;
349        if (nodesearch == NODESEARCH_NONTERMINALS && children.length==0 ||  // I'm a leaf, don't include me
350            nodesearch == NODESEARCH_TERMINALS && children.length > 0)  // I'm a nonleaf, don't include me
351            sum = 0;
352           
353        for(int x=0;x<children.length;x++)
354            sum += pathLength(nodesearch, currentDepth + 1);
355        return sum;
356        }
357       
358    /** Returns the mean depth of the tree, which is path length (sum of all paths from all nodes to the root) divided by the number of nodes.  O(n). */
359    int meanDepth(int nodesearch)
360        {
361        return pathLength(nodesearch) / numNodes(nodesearch);
362        }
363
364    /** Returns the depth at which I appear in the tree, which is a value >= 0. O(ln n) avg.*/
365    public int atDepth()
366        {
367        // -- new code, no need for recursion
368        GPNodeParent cparent = parent;
369        int count=0;
370
371        while(cparent!=null && cparent instanceof GPNode)
372            {
373            count++;
374            cparent = ((GPNode)(cparent)).parent;
375            }
376        return count;
377
378        /* // -- old code
379           if (parent==null) return 0;
380           if (!(parent instanceof GPNode))  // found the root!
381           return 0;
382           else return 1 + ((GPNode)parent).atDepth();
383        */
384        }
385
386    /** Returns the p'th node, constrained by nodesearch,
387        in the subtree for which this GPNode is root.
388        Use numNodes(nodesearch) to determine the total number.  Or if
389        you used numNodes(g), then when
390        nodesearch == NODESEARCH_CUSTOM, g.test(...) is used
391        as the constraining predicate.
392        p ranges from 0 to this number minus 1. O(n). The
393        resultant node is returned in <i>g</i>.*/
394    public int nodeInPosition(int p, final GPNodeGatherer g, final int nodesearch)
395        {
396        // am I of the type I'm looking for?
397        if (nodesearch==NODESEARCH_ALL ||
398            (nodesearch==NODESEARCH_TERMINALS && children.length==0) ||
399            (nodesearch==NODESEARCH_NONTERMINALS && children.length>0) ||
400            (nodesearch==NODESEARCH_CUSTOM && g.test(this)))
401            {
402            // is the count now at 0?  Is it me?
403            if (p==0)
404                {
405                g.node = this;
406                return -1; // found it
407                }
408            // if it's not me, drop the count by 1
409            else p--;
410            }
411       
412        // regardless, check my children if I've not returned by now
413        for(int x=0;x<children.length;x++)
414            {
415            p = children[x].nodeInPosition(p,g,nodesearch);
416            if (p==-1) return -1; // found it
417            }
418        return p;
419        }
420
421    /** Returns the root ancestor of this node.  O(ln n) average case,
422        O(n) worst case. */
423
424    public GPNodeParent rootParent()
425        {
426
427        // -- new code, no need for recursion
428        GPNodeParent cparent = this;
429        while(cparent!=null && cparent instanceof GPNode)
430            cparent = ((GPNode)(cparent)).parent;
431        return cparent;
432        }
433
434    /** Returns true if the subtree rooted at this node contains subnode.  O(n). */
435    public boolean contains(final GPNode subnode)
436        {
437        if (subnode==this) return true;
438        for(int x=0;x<children.length;x++)
439            if (children[x].contains(subnode)) return true;
440        return false;
441        }
442
443
444    /** Starts a node in a new life immediately after it has been cloned.
445        The default version of this function does nothing.  The purpose of
446        this function is to give ERCs a chance to set themselves to a new
447        random value after they've been cloned from the prototype.
448        You should not assume that the node is properly connected to other
449        nodes in the tree at the point this method is called. */
450
451    public void resetNode(final EvolutionState state, final int thread) { }
452
453    /** A convenience function for identifying a GPNode in an error message */
454    public String errorInfo() { return "GPNode " + toString() + " in the function set for tree " + ((GPTree)(rootParent())).treeNumber(); }
455
456
457    public GPNode lightClone()
458        {
459        try
460            {
461            GPNode obj = (GPNode)(super.clone());
462            int len = children.length;
463            if (len == 0) obj.children = children;  // we'll share arrays -- probably just using GPNodeConstraints.zeroChildren anyway
464            else obj.children = new GPNode[len];
465            return obj;
466            }
467        catch (CloneNotSupportedException e)
468            { throw new InternalError(); } // never happens
469        }
470
471    /** Deep-clones the tree rooted at this node, and returns the entire
472        copied tree.  The result has everything set except for the root
473        node's parent and argposition.  This method is identical to
474        cloneReplacing for historical reasons, except that it returns
475        the object as an Object, not a GPNode. */   
476 
477    public Object clone()
478        {
479        GPNode newnode = (GPNode)(lightClone());
480        for(int x=0;x<children.length;x++)
481            {
482            newnode.children[x] = (GPNode)(children[x].cloneReplacing());
483            // if you think about it, the following CAN'T be implemented by
484            // the children's clone method.  So it's set here.
485            newnode.children[x].parent = newnode;
486            newnode.children[x].argposition = (byte)x;
487            }
488        return newnode;
489        }
490
491    /** Deep-clones the tree rooted at this node, and returns the entire
492        copied tree.  The result has everything set except for the root
493        node's parent and argposition.  This method is identical to
494        cloneReplacing for historical reasons, except that it returns
495        the object as a GPNode, not an Object.
496        @deprecated use clone() instead.
497    */   
498 
499    public final GPNode cloneReplacing()
500        {
501        return (GPNode)clone();
502        }
503
504
505    /** Deep-clones the tree rooted at this node, and returns the entire
506        copied tree.  If the node oldSubtree is located somewhere in this
507        tree, then its subtree is replaced with a deep-cloned copy of
508        newSubtree.  The result has everything set except for the root
509        node's parent and argposition. */
510 
511    public final GPNode cloneReplacing(final GPNode newSubtree, final GPNode oldSubtree)
512        {
513        if (this==oldSubtree)
514            return newSubtree.cloneReplacing();
515        else
516            {
517            GPNode newnode = (GPNode)(lightClone());
518            for(int x=0;x<children.length;x++)
519                {
520                newnode.children[x] = (GPNode)(children[x].cloneReplacing(newSubtree,oldSubtree));
521                // if you think about it, the following CAN'T be implemented by
522                // the children's clone method.  So it's set here.
523                newnode.children[x].parent = newnode;
524                newnode.children[x].argposition = (byte)x;
525                }
526            return newnode;     
527            }
528        }
529
530
531
532    /** Deep-clones the tree rooted at this node, and returns the entire
533        copied tree.  If the node oldSubtree is located somewhere in this
534        tree, then its subtree is replaced with
535        newSubtree (<i>not</i> a copy of newSubtree). 
536        The result has everything set except for the root
537        node's parent and argposition. */
538 
539    public final GPNode cloneReplacingNoSubclone(final GPNode newSubtree, final GPNode oldSubtree)
540        {
541        if (this==oldSubtree)
542            {
543            return newSubtree;
544            }
545        else
546            {
547            GPNode newnode = (GPNode)(lightClone());
548            for(int x=0;x<children.length;x++)
549                {
550                newnode.children[x] = (GPNode)(children[x].cloneReplacingNoSubclone(newSubtree,oldSubtree));
551                // if you think about it, the following CAN'T be implemented by
552                // the children's clone method.  So it's set here.
553                newnode.children[x].parent = newnode;
554                newnode.children[x].argposition = (byte)x;
555                }
556            return newnode;     
557            }
558        }
559
560
561
562
563
564
565    /** Deep-clones the tree rooted at this node, and returns the entire
566        copied tree.  If a node in oldSubtrees is located somewhere in this
567        tree, then its subtree is replaced with a deep-cloned copy of the
568        subtree rooted at its equivalent number in
569        newSubtrees.  The result has everything set except for the root
570        node's parent and argposition. */
571 
572    public final GPNode cloneReplacing(final GPNode[] newSubtrees, final GPNode[] oldSubtrees)
573        {
574        // am I a candidate?
575        int candidate = -1;
576        for(int x=0;x<oldSubtrees.length;x++)
577            if (this==oldSubtrees[x]) { candidate=x; break; }
578
579        if (candidate >= 0)
580            return newSubtrees[candidate].cloneReplacing(newSubtrees,oldSubtrees);
581        else
582            {
583            GPNode newnode = (GPNode)(lightClone());
584            for(int x=0;x<children.length;x++)
585                {
586                newnode.children[x] = (GPNode)(children[x].cloneReplacing(newSubtrees,oldSubtrees));
587                // if you think about it, the following CAN'T be implemented by
588                // the children's clone method.  So it's set here.
589                newnode.children[x].parent = newnode;
590                newnode.children[x].argposition = (byte)x;
591                }
592            return newnode;     
593            }
594        }
595
596
597   
598    /** Clones a new subtree, but with the single node oldNode
599        (which may or may not be in the subtree)
600        replaced with a newNode (not a clone of newNode). 
601        These nodes should be
602        type-compatible both in argument and return types, and should have
603        the same number of arguments obviously.  This function will <i>not</i>
604        check for this, and if they are not the result is undefined. */
605
606
607    public final GPNode cloneReplacingAtomic(final GPNode newNode, final GPNode oldNode)
608        {
609        int numArgs;
610        GPNode curnode;
611        if (this==oldNode)
612            {
613            numArgs = Math.max(newNode.children.length,children.length);
614            curnode = newNode;
615            }
616        else
617            {
618            numArgs = children.length;
619            curnode = (GPNode)lightClone();
620            }
621
622        // populate
623
624        for(int x=0;x<numArgs;x++)
625            {
626            curnode.children[x] = (GPNode)(children[x].cloneReplacingAtomic(newNode,oldNode));
627            // if you think about it, the following CAN'T be implemented by
628            // the children's clone method.  So it's set here.
629            curnode.children[x].parent = curnode;
630            curnode.children[x].argposition = (byte)x;
631            }
632        return curnode;
633        }
634
635
636
637
638
639    /** Clones a new subtree, but with each node in oldNodes[] respectively
640        (which may or may not be in the subtree) replaced with
641        the equivalent
642        nodes in newNodes[] (and not clones). 
643        The length of oldNodes[] and newNodes[] should
644        be the same of course.  These nodes should be
645        type-compatible both in argument and return types, and should have
646        the same number of arguments obviously.  This function will <i>not</i>
647        check for this, and if they are not the result is undefined. */
648
649
650    public final GPNode cloneReplacingAtomic(final GPNode[] newNodes, final GPNode[] oldNodes)
651        {
652        int numArgs;
653        GPNode curnode;
654        int found = -1;
655       
656        for(int x=0;x<newNodes.length;x++)
657            {
658            if (this==oldNodes[x]) { found=x; break; }
659            }
660
661        if (found > -1)
662            {
663            numArgs = Math.max(newNodes[found].children.length,
664                children.length);
665            curnode = newNodes[found];
666            }
667        else
668            {
669            numArgs = children.length;
670            curnode = (GPNode)lightClone();
671            }
672
673        // populate
674
675        for(int x=0;x<numArgs;x++)
676            {
677            curnode.children[x] = (GPNode)(children[x].cloneReplacingAtomic(newNodes,oldNodes));
678            // if you think about it, the following CAN'T be implemented by
679            // the children's clone method.  So it's set here.
680            curnode.children[x].parent = curnode;
681            curnode.children[x].argposition = (byte)x;
682            }
683        return curnode;
684        }
685
686
687
688
689
690    /** Replaces the node with another node in its position in the tree.
691        newNode should already have been cloned and ready to go.
692        We presume that the other node is type-compatible and
693        of the same arity (these things aren't checked).  */
694       
695    public final void replaceWith(final GPNode newNode)
696        {
697        // copy the parent and argposition
698        newNode.parent = parent;
699        newNode.argposition = argposition;
700       
701        // replace the parent pointer
702        if (parent instanceof GPNode)
703            ((GPNode)(parent)).children[argposition] = newNode;
704        else
705            ((GPTree)(parent)).child = newNode;
706           
707        // replace the child pointers
708        for(byte x = 0;x<children.length;x++)
709            {
710            newNode.children[x] = children[x];
711            newNode.children[x].parent = newNode;
712            newNode.children[x].argposition = x;
713            }
714        }
715   
716    /** Returns true if I and the provided node are the same kind of
717        node -- that is, we could have both been cloned() and reset() from
718        the same prototype node.  The default form of this function returns
719        true if I and the node have the same class, the same length children
720        array, and the same constraints.  You may wish to override this in
721        certain circumstances.   Here's an example of how nodeEquivalentTo(node)
722        differs from nodeEquals(node): two ERCs, both of
723        the same class, but one holding '1.23' and the other holding '2.45', which
724        came from the same prototype node in the same function set.
725        They should NOT be nodeEquals(...) but *should* be nodeEquivalent(...). */
726    public boolean nodeEquivalentTo(GPNode node)
727        {
728        return (this.getClass().equals(node.getClass()) &&
729            children.length == node.children.length &&
730            constraints == node.constraints);
731        }
732
733
734    /** Returns a hashcode usually associated with all nodes that are
735        equal to you (using nodeEquals(...)).  The default form
736        of this method returns the hashcode of the node's class.
737        ERCs in particular probably will want to override this method.
738    */
739    public int nodeHashCode()
740        {
741        return (this.getClass().hashCode());
742        }
743
744    /** Returns a hashcode associated with all the nodes in the tree. 
745        The default version adds the hash of the node plus its child
746        trees, rotated one-off each time, which seems reasonable. */
747    public int rootedTreeHashCode()
748        {
749        int hash = nodeHashCode();
750
751        for(int x=0;x<children.length;x++)
752            // rotate hash and XOR
753            hash =
754                (hash << 1 | hash >>> 31 ) ^
755                children[x].rootedTreeHashCode();
756        return hash;
757        }
758
759    /** Returns true if I am the "genetically" identical to this node, and our
760        children arrays are the same length, though
761        we may have different parents and children.  The default form
762        of this method simply calls the much weaker nodeEquivalentTo(node). 
763        You may need to override this to perform exact comparisons, if you're
764        an ERC, ADF, or ADM for example.  Here's an example of how nodeEquivalentTo(node)
765        differs from nodeEquals(node): two ERCs, both of
766        the same class, but one holding '1.23' and the other holding '2.45', which
767        came from the same prototype node in the same function set.
768        They should NOT be nodeEquals(...) but *should* be nodeEquivalent(...).  */
769    public boolean nodeEquals(final GPNode node)
770        {
771        return nodeEquivalentTo(node);
772        }
773
774    /** Returns true if the two rooted trees are "genetically" equal, though
775        they may have different parents.  O(n). */
776    public boolean rootedTreeEquals(final GPNode node)
777        {
778        if (!nodeEquals(node)) return false;
779        for (int x=0;x<children.length;x++)
780            if (!(children[x].rootedTreeEquals(node.children[x])))
781                return false;
782        return true;
783        }
784
785    /** Prints out a human-readable and Lisp-like atom for the node,
786        and returns the number of bytes in the string that you sent
787        to the log (use print(),
788        not println()).  The default version gets the atom from
789        toStringForHumans().
790    */
791    public int printNodeForHumans(final EvolutionState state,
792        final int log)
793        {
794        return printNodeForHumans(state, log, Output.V_VERBOSE);
795        }
796
797    /** Prints out a human-readable and Lisp-like atom for the node,
798        and returns the number of bytes in the string that you sent
799        to the log (use print(),
800        not println()).  The default version gets the atom from
801        toStringForHumans().
802        @deprecated Verbosity no longer has an effect.
803    */
804    public int printNodeForHumans(final EvolutionState state,
805        final int log,
806        final int verbosity)
807        {
808        String n = toStringForHumans();
809        state.output.print(n,log);
810        return n.length();
811        }
812
813
814    /** Prints out a COMPUTER-readable and Lisp-like atom for the node, which
815        is also suitable for readNode to read, and returns
816        the number of bytes in the string that you sent to the log (use print(),
817        not println()).  The default version gets the atom from toString().
818        O(1).
819    */
820    public int printNode(final EvolutionState state, final int log)
821        {
822        printNode(state, log, Output.V_VERBOSE);
823        String n = toString();
824        return n.length();
825        }
826
827    /** Prints out a COMPUTER-readable and Lisp-like atom for the node, which
828        is also suitable for readNode to read, and returns
829        the number of bytes in the string that you sent to the log (use print(),
830        not println()).  The default version gets the atom from toString().
831        O(1).
832        @deprecated Verbosity no longer has an effect.
833    */
834    public int printNode(final EvolutionState state, final int log,
835        final int verbosity)
836        {
837        String n = toString();
838        state.output.print(n,log);
839        return n.length();
840        }
841
842
843    /** Prints out a COMPUTER-readable and Lisp-like atom for the node, which
844        is also suitable for readNode to read, and returns
845        the number of bytes in the string that you sent to the log (use print(),
846        not println()).  The default version gets the atom from toString().
847        O(1). */
848
849    public int printNode(final EvolutionState state,
850        final PrintWriter writer)
851        {
852        String n = toString();
853        writer.print(n);
854        return n.length();
855        }
856               
857    /** Returns a Lisp-like atom for the node and any nodes of the same class.
858        This will almost always be identical to the result of toString() (and the default
859        does exactly this), but for ERCs it'll be different: toString will include the
860        encoded constant data, whereas name() will not include this information and will
861        be the same for all ERCs of this type.  If two nodes are nodeEquivalentTo(...)
862        each other, then they will have the same name().  If two nodes are nodeEquals(...)
863        each other, then they will have the same toString().  */
864               
865    public String name() { return toString(); }
866
867    /** Returns a Lisp-like atom for the node which can be read in again by computer.
868        If you need to encode an integer or a float or whatever for some reason
869        (perhaps if it's an ERC), you should use the ec.util.Code library.  */
870
871    public abstract String toString();
872
873    /** Returns a Lisp-like atom for the node which is intended for human
874        consumption, and not to be read in again.  The default version
875        just calls toString(). */
876
877    public String toStringForHumans() { return toString(); }
878
879    /** Returns a description of the node that can make it easy to identify
880        in error messages (by default, at least its name and the tree it's found in).
881        It's okay if this is a reasonably expensive procedure -- it won't be called
882        a lot.  */
883
884    public String toStringForError()
885        {
886        GPTree rootp = (GPTree)rootParent();
887        if (rootp!=null)
888            {
889            int tnum = ((GPTree)(rootParent())).treeNumber();
890            return toString() + (tnum == GPTree.NO_TREENUM ? "" : " in tree " + tnum);
891            }
892        else return toString();
893        }
894
895    /** Produces the Graphviz code for a Graphviz tree of the subtree rooted at this node.
896        For this to work, the output of toString() must not contain a double-quote.
897        Note that this isn't particularly efficient and should only be used to generate
898        occasional trees for display, not for storing individuals or sending them over networks. */
899    public String makeGraphvizTree()
900        {
901        return "digraph g {\nnode [shape=rectangle];\n" + makeGraphvizSubtree("n") + "}\n";
902        }
903   
904    /** Produces the inner code for a graphviz subtree.  Called from makeGraphvizTree().
905        Note that this isn't particularly efficient and should only be used to generate
906        occasional trees for display, not for storing individuals or sending them over networks. */
907    protected String makeGraphvizSubtree(String prefix)
908        {
909        String body = prefix + "[label = \"" + toStringForHumans() + "\"];\n";
910        for(int x = 0; x < children.length; x++)
911            {
912            String newprefix;
913            if (x < 10) newprefix = prefix + x;
914            else newprefix = prefix + "n" + x;  // to distinguish it
915           
916            body = body + children[x].makeGraphvizSubtree(newprefix);
917            body = body + prefix + " -> " + newprefix + ";\n";
918            }
919        return body;
920        }
921
922    /** Produces the LaTeX code for a LaTeX tree of the subtree rooted at this node, using the <tt>epic</tt>
923        and <tt>fancybox</tt> packages, as described in sections 10.5.2 (page 307)
924        and 10.1.3 (page 278) of <i>The LaTeX Companion</i>, respectively.  For this to
925        work, the output of toStringForHumans() must not contain any weird latex characters, notably { or } or % or \,
926        unless you know what you're doing. See the documentation for ec.gp.GPTree for information
927        on how to take this code snippet and insert it into your LaTeX file.
928        Note that this isn't particularly efficient and should only be used to generate
929        occasional trees for display, not for storing individuals or sending them over networks. */
930   
931    public String makeLatexTree()
932        {
933        if (children.length==0)
934            return "\\gpbox{"+toStringForHumans()+"}";
935           
936        String s = "\\begin{bundle}{\\gpbox{"+toStringForHumans()+"}}";
937        for(int x=0;x<children.length;x++)
938            s = s + "\\chunk{"+children[x].makeLatexTree()+"}";
939        s = s + "\\end{bundle}";
940        return s;
941        }
942       
943    /** Producess a String consisting of the tree in pseudo-C form, given that the parent already will wrap the
944        expression in parentheses (or not).  In pseudo-C form, functions with one child are printed out as a(b),
945        functions with more than two children are printed out as a(b, c, d, ...), and functions with exactly two
946        children are either printed as a(b, c) or in operator form as (b a c) -- for example, (b * c).  Whether
947        or not to do this depends on the setting of <tt>useOperatorForm</tt>.  Additionally, terminals will be
948        printed out either in variable form -- a -- or in zero-argument function form -- a() -- depending on
949        the setting of <tt>printTerminalsAsVariables</tt>.
950        Note that this isn't particularly efficient and should only be used to generate
951        occasional trees for display, not for storing individuals or sending them over networks.
952    */
953               
954    public String makeCTree(boolean parentMadeParens, boolean printTerminalsAsVariables, boolean useOperatorForm)
955        {
956        if (children.length==0)
957            return (printTerminalsAsVariables ? toStringForHumans() : toStringForHumans() + "()");
958        else if (children.length==1)
959            return toStringForHumans() + "(" + children[0].makeCTree(true, printTerminalsAsVariables, useOperatorForm) + ")";
960        else if (children.length==2 && useOperatorForm)
961            return (parentMadeParens ? "" : "(") +
962                children[0].makeCTree(false, printTerminalsAsVariables, useOperatorForm) + " " +
963                toStringForHumans() + " " + children[1].makeCTree(false, printTerminalsAsVariables, useOperatorForm) +
964                (parentMadeParens ? "" : ")");
965        else
966            {
967            String s = toStringForHumans() + "(" + children[0].makeCTree(true, printTerminalsAsVariables, useOperatorForm);
968            for(int x = 1; x < children.length;x++)
969                s = s + ", " + children[x].makeCTree(true, printTerminalsAsVariables, useOperatorForm);
970            return s + ")";
971            }
972        }
973
974    /**
975       Produces a tree for human consumption in Lisp form similar to that generated by printTreeForHumans().
976       Note that this isn't particularly efficient and should only be used to generate
977       occasional trees for display, not for storing individuals or sending them over networks.
978    */
979    public String makeLispTree()
980        {
981        if (children.length==0)
982            return toStringForHumans();
983        else
984            {
985            String s = "(" + toStringForHumans();
986            for(int x=0;x<children.length;x++)
987                s = s + " " + children[x].makeLispTree();
988            return s + ")";
989            }
990        }
991
992
993    /** Prints out the tree on a single line, with no ending \n, in a fashion that can
994        be read in later by computer. O(n). 
995        You should call this method with printbytes == 0.
996    */
997   
998    public int printRootedTree(final EvolutionState state,
999        final int log, int printbytes)
1000        {
1001        return printRootedTree(state, log, Output.V_VERBOSE, printbytes);
1002        }
1003
1004
1005    /** Prints out the tree on a single line, with no ending \n, in a fashion that can
1006        be read in later by computer. O(n). 
1007        You should call this method with printbytes == 0.
1008        @Deprecated Verbosity no longer has an effect.
1009    */
1010   
1011    public int printRootedTree(final EvolutionState state,
1012        final int log, final int verbosity,
1013        int printbytes)
1014        {
1015        if (children.length>0) { state.output.print(" (",verbosity,log); printbytes += 2; }
1016        else { state.output.print(" ",log); printbytes += 1; }
1017
1018        printbytes += printNode(state,log);
1019
1020        for (int x=0;x<children.length;x++)
1021            printbytes = children[x].printRootedTree(state,log,printbytes);
1022        if (children.length>0) { state.output.print(")",log); printbytes += 1; }
1023        return printbytes;
1024        }
1025
1026
1027    /** Prints out the tree on a single line, with no ending \n, in a fashion that can
1028        be read in later by computer. O(n).  Returns the number of bytes printed.
1029        You should call this method with printbytes == 0. */
1030   
1031    public int printRootedTree(final EvolutionState state, final PrintWriter writer,
1032        int printbytes)
1033        {
1034        if (children.length>0) { writer.print(" ("); printbytes += 2; }
1035        else { writer.print(" "); printbytes += 1; }
1036
1037        printbytes += printNode(state,writer);
1038
1039        for (int x=0;x<children.length;x++)
1040            printbytes = children[x].printRootedTree(state,writer,printbytes);
1041        if (children.length>0) { writer.print(")"); printbytes += 1; }
1042        return printbytes;
1043        }
1044
1045
1046    /** Prints out the tree in a readable Lisp-like multi-line fashion. O(n). 
1047        You should call this method with tablevel and printbytes == 0. 
1048        No ending '\n' is printed. 
1049    */
1050   
1051    public int printRootedTreeForHumans(final EvolutionState state, final int log,
1052        int tablevel, int printbytes)
1053        {
1054        return printRootedTreeForHumans(state, log, Output.V_VERBOSE, tablevel, printbytes);
1055        }
1056
1057    /** Prints out the tree in a readable Lisp-like multi-line fashion. O(n). 
1058        You should call this method with tablevel and printbytes == 0. 
1059        No ending '\n' is printed. 
1060        @deprecated Verbosity no longer has an effect.
1061    */
1062   
1063    public int printRootedTreeForHumans(final EvolutionState state, final int log,
1064        final int verbosity,
1065        int tablevel, int printbytes)
1066        {
1067        if (printbytes>MAXPRINTBYTES)
1068            {
1069            state.output.print("\n",log);
1070            tablevel++;
1071            printbytes = 0;
1072            for(int x=0;x<tablevel;x++)
1073                state.output.print(GPNODEPRINTTAB,log);
1074            }
1075
1076        if (children.length>0) { state.output.print(" (",log); printbytes += 2; }
1077        else { state.output.print(" ",log); printbytes += 1; }
1078
1079        printbytes += printNodeForHumans(state,log);
1080
1081        for (int x=0;x<children.length;x++)
1082            printbytes = children[x].printRootedTreeForHumans(state,log,tablevel,printbytes);
1083        if (children.length>0) { state.output.print(")",log); printbytes += 1; }
1084        return printbytes;
1085        }
1086
1087
1088    /** Reads the node symbol,
1089        advancing the DecodeReturn to the first character in the string
1090        beyond the node symbol, and returns a new, empty GPNode of the
1091        appropriate class representing that symbol, else null if the
1092        node symbol is not of the correct type for your GPNode class. You may
1093        assume that initial whitespace has been eliminated.  Generally should
1094        be case-SENSITIVE, unlike in Lisp.  The default
1095        version usually works for "simple" function names, that is, not ERCs
1096        or other stuff where you have to encode the symbol. */
1097    public GPNode readNode(DecodeReturn dret)
1098        {
1099        int len = dret.data.length();
1100
1101        // get my name
1102        String str2 = toString();
1103        int len2 = str2.length();
1104
1105        if (dret.pos + len2 > len)  // uh oh, not enough space
1106            return null;
1107
1108        // check it out
1109        for(int x=0; x < len2 ; x++)
1110            if (dret.data.charAt(dret.pos + x) != str2.charAt(x))
1111                return null;
1112
1113        // looks good!  Check to make sure that
1114        // the symbol's all there is
1115        if (dret.data.length() > dret.pos+len2)
1116            {
1117            char c = dret.data.charAt(dret.pos+len2);
1118            if (!Character.isWhitespace(c) &&
1119                c != ')' && c != '(') // uh oh
1120                return null;
1121            }
1122
1123        // we're happy!
1124        dret.pos += len2;
1125        return (GPNode)lightClone();
1126        }
1127
1128
1129    public void writeRootedTree(final EvolutionState state,final GPType expectedType,
1130        final GPFunctionSet set, final DataOutput dataOutput) throws IOException
1131        {
1132        dataOutput.writeInt(children.length);
1133        boolean isTerminal = (children.length == 0);
1134
1135        // identify the node
1136        GPNode[] gpfi = isTerminal ?
1137            set.terminals[expectedType.type] :
1138            set.nonterminals[expectedType.type];
1139       
1140        int index=0;
1141        for( /*int index=0 */; index <gpfi.length;index++)
1142            if ((gpfi[index].nodeEquivalentTo(this))) break;
1143       
1144        if (index==gpfi.length)  // uh oh
1145            state.output.fatal("No node in the function set can be found that is equivalent to the node " + this +     
1146                " when performing writeRootedTree(EvolutionState, GPType, GPFunctionSet, DataOutput).");
1147        dataOutput.writeInt(index);  // what kind of node it is
1148        writeNode(state,dataOutput);
1149
1150        GPInitializer initializer = ((GPInitializer)state.initializer);       
1151        for(int x=0;x<children.length;x++)
1152            children[x].writeRootedTree(state,constraints(initializer).childtypes[x],set,dataOutput);
1153        }
1154
1155
1156    public static GPNode readRootedTree(final EvolutionState state,
1157        final DataInput dataInput,
1158        GPType expectedType,
1159        GPFunctionSet set,
1160        GPNodeParent parent,
1161        int argposition) throws IOException
1162        {
1163        int len = dataInput.readInt();      // num children
1164        int index = dataInput.readInt();    // index in function set
1165       
1166        boolean isTerminal = (len == 0);
1167        GPNode[] gpfi = isTerminal ?
1168            set.terminals[expectedType.type] :
1169            set.nonterminals[expectedType.type];
1170
1171        GPNode node = ((GPNode)(gpfi[index].lightClone()));
1172       
1173        if (node.children == null || node.children.length != len)
1174            state.output.fatal("Mismatch in number of children (" + len +
1175                ") when performing readRootedTree(...DataInput...) on " + node);
1176       
1177        node.parent = parent;
1178        node.argposition = (byte)argposition;
1179        node.readNode(state,dataInput);
1180
1181        // do its children
1182        GPInitializer initializer = ((GPInitializer)state.initializer);       
1183        for(int x=0;x<node.children.length;x++)
1184            node.children[x] = readRootedTree(state,dataInput,node.constraints(initializer).childtypes[x],set, node, x);
1185
1186        return node;
1187        }
1188
1189    /** Override this to write any additional node-specific information to dataOutput besides: the number of arguments,
1190        the specific node class, the children, and the parent.  The default version of this method does nothing. */
1191    public void writeNode(final EvolutionState state, final DataOutput dataOutput) throws IOException
1192        {
1193        // do nothing
1194        }
1195       
1196    /** Override this to read any additional node-specific information from dataInput besides: the number of arguments,
1197        the specific node class, the children, and the parent.  The default version of this method does nothing. */
1198    public void readNode(final EvolutionState state, final DataInput dataInput) throws IOException
1199        {
1200        // do nothing
1201        }
1202
1203    /** Reads the node and its children from the form printed out by printRootedTree. */
1204    public static GPNode readRootedTree(int linenumber,
1205        DecodeReturn dret,
1206        GPType expectedType,
1207        GPFunctionSet set,
1208        GPNodeParent parent,
1209        int argposition,
1210        EvolutionState state)
1211        {
1212        final char REPLACEMENT_CHAR = '@';
1213
1214        // eliminate whitespace if any
1215        boolean isTerminal = true;
1216        int len = dret.data.length();
1217        for(  ;  dret.pos < len &&
1218                  Character.isWhitespace(dret.data.charAt(dret.pos)) ; dret.pos++);
1219       
1220        // if I'm out of space, complain
1221       
1222        if (dret.pos >= len)
1223            state.output.fatal("Reading line " + linenumber + ": " + "Premature end of tree structure -- did you forget a close-parenthesis?\nThe tree was" + dret.data);
1224         
1225        // if I've found a ')', complain
1226        if (dret.data.charAt(dret.pos) == ')')
1227            {
1228            StringBuffer sb = new StringBuffer(dret.data);
1229            sb.setCharAt(dret.pos,REPLACEMENT_CHAR);
1230            dret.data = sb.toString();
1231            state.output.fatal("Reading line " + linenumber + ": " + "Premature ')' which I have replaced with a '" + REPLACEMENT_CHAR + "', in tree:\n" + dret.data);
1232            }
1233       
1234        // determine if I'm a terminal or not
1235        if (dret.data.charAt(dret.pos) == '(')
1236            {
1237            isTerminal=false;
1238            dret.pos++;
1239            // strip following whitespace
1240            for(  ;  dret.pos < len &&
1241                      Character.isWhitespace(dret.data.charAt(dret.pos)) ; dret.pos++);
1242            }
1243       
1244        // check again if I'm out of space
1245       
1246        if (dret.pos >= len)
1247            state.output.fatal("Reading line " + linenumber + ": " + "Premature end of tree structure -- did you forget a close-parenthesis?\nThe tree was" + dret.data);
1248       
1249        // check again if I found a ')'
1250        if (dret.data.charAt(dret.pos) == ')')
1251            {
1252            StringBuffer sb = new StringBuffer(dret.data);
1253            sb.setCharAt(dret.pos,REPLACEMENT_CHAR);
1254            dret.data = sb.toString();
1255            state.output.fatal("Reading line " + linenumber + ": " + "Premature ')' which I have replaced with a '" + REPLACEMENT_CHAR + "', in tree:\n" + dret.data);
1256            }
1257       
1258       
1259        // find that node!
1260        GPNode[] gpfi = isTerminal ?
1261            set.terminals[expectedType.type] :
1262            set.nonterminals[expectedType.type];
1263       
1264        GPNode node = null;
1265        for(int x=0;x<gpfi.length;x++)
1266            if ((node = gpfi[x].readNode(dret)) != null) break;
1267       
1268        // did I find one?
1269       
1270        if (node==null)
1271            {
1272            if (dret.pos!=0)
1273                {
1274                StringBuffer sb = new StringBuffer(dret.data);
1275                sb.setCharAt(dret.pos,REPLACEMENT_CHAR);
1276                dret.data = sb.toString();
1277                }
1278            else dret.data = "" + REPLACEMENT_CHAR + dret.data;
1279            state.output.fatal("Reading line " + linenumber + ": " + "I came across a symbol which I could not match up with a type-valid node.\nI have replaced the position immediately before the node in question with a '" + REPLACEMENT_CHAR + "':\n" + dret.data);
1280            }
1281       
1282        node.parent = parent;
1283        node.argposition = (byte)argposition;
1284        GPInitializer initializer = ((GPInitializer)state.initializer);
1285       
1286        // do its children
1287        for(int x=0;x<node.children.length;x++)
1288            node.children[x] = readRootedTree(linenumber,dret,node.constraints(initializer).childtypes[x],set,node,x,state);
1289       
1290        // if I'm not a terminal, look for a ')'
1291       
1292        if (!isTerminal)
1293            {
1294            // clear whitespace
1295            for(  ;  dret.pos < len &&
1296                      Character.isWhitespace(dret.data.charAt(dret.pos)) ; dret.pos++);
1297           
1298            if (dret.pos >= len)
1299                state.output.fatal("Reading line " + linenumber + ": " + "Premature end of tree structure -- did you forget a close-parenthesis?\nThe tree was" + dret.data);
1300           
1301            if (dret.data.charAt(dret.pos) != ')')
1302                {
1303                if (dret.pos!=0)
1304                    {
1305                    StringBuffer sb = new StringBuffer(dret.data);
1306                    sb.setCharAt(dret.pos,REPLACEMENT_CHAR);
1307                    dret.data = sb.toString();
1308                    }
1309                else dret.data = "" + REPLACEMENT_CHAR + dret.data;
1310                state.output.fatal("Reading line " + linenumber + ": " + "A nonterminal node has too many arguments.  I have put a '" +
1311                    REPLACEMENT_CHAR + "' just before the offending argument.\n" + dret.data);
1312                }
1313            else dret.pos++;  // get rid of the ')'
1314            }
1315       
1316        // return the node
1317        return node;
1318        }
1319   
1320
1321    /** Evaluates the node with the given thread, state, individual, problem, and stack.
1322        Your random number generator will be state.random[thread]. 
1323        The node should, as appropriate, evaluate child nodes with these same items
1324        passed to eval(...).
1325
1326        <p>About <b>input</b>: <tt>input</tt> is special; it is how data is passed between
1327        parent and child nodes.  If children "receive" data from their parent node when
1328        it evaluates them, they should receive this data stored in <tt>input</tt>.
1329        If (more likely) the parent "receives" results from its children, it should
1330        pass them an <tt>input</tt> object, which they'll fill out, then it should
1331        check this object for the returned value.
1332
1333        <p>A tree is typically evaluated by dropping a GPData into the root.  When the
1334        root returns, the resultant <tt>input</tt> should hold the return value.
1335
1336        <p>In general, you should not be creating new GPDatas. 
1337        If you think about it, in most conditions (excepting ADFs and ADMs) you
1338        can use and reuse <tt>input</tt> for most communications purposes between
1339        parents and children. 
1340
1341        <p>So, let's say that your GPNode function implements the boolean AND function,
1342        and expects its children to return return boolean values (as it does itself).
1343        You've implemented your GPData subclass to be, uh, <b>BooleanData</b>, which
1344        looks like
1345       
1346        * <tt><pre>public class BooleanData extends GPData
1347        *    {
1348        *    public boolean result;
1349        *    public GPData copyTo(GPData gpd)
1350        *      {
1351        *      ((BooleanData)gpd).result = result;
1352        *      }
1353        *    }</pre></tt>
1354
1355        <p>...so, you might implement your eval(...) function as follows:
1356
1357        * <tt><pre>public void eval(final EvolutionState state,
1358        *                     final int thread,
1359        *                     final GPData input,
1360        *                     final ADFStack stack,
1361        *                     final GPIndividual individual,
1362        *                     final Problem problem
1363        *    {
1364        *    BooleanData dat = (BooleanData)input;
1365        *    boolean x;
1366        *
1367        *    // evaluate the first child
1368        *    children[0].eval(state,thread,input,stack,individual,problem);
1369        * 
1370        *    // store away its result
1371        *    x = dat.result;
1372        *
1373        *    // evaluate the second child
1374        *    children[1].eval(state,thread,input,stack,individual,problem);
1375        *
1376        *    // return (in input) the result of the two ANDed
1377        *
1378        *    dat.result = dat.result && x;
1379        *    return;
1380        *    }
1381        </pre></tt>
1382    */
1383   
1384    public abstract void eval(final EvolutionState state,
1385        final int thread,
1386        final GPData input,
1387        final ADFStack stack,
1388        final GPIndividual individual,
1389        final Problem problem);
1390    }
1391
Note: See TracBrowser for help on using the repository browser.