Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OKBJavaConnector/ECJClient/src/ec/gp/GPTree.java @ 11194

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

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

File size: 18.7 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
8
9package ec.gp;
10import ec.*;
11import ec.util.*;
12import java.io.*;
13
14/*
15 * GPTree.java
16 *
17 * Created: Fri Aug 27 17:14:02 1999
18 * By: Sean Luke
19 */
20
21/**
22 * GPTree is a GPNodeParent which holds the root GPNode of a tree
23 * of GPNodes.  GPTrees typically fill out an array held in a GPIndividual
24 * (their "owner") and their roots are evaluated to evaluate a Genetic
25 * programming tree.
26 *
27 * GPTrees also have <i>constraints</i>, which are shared, and define items
28 * shared among several GPTrees.
29
30 * <p>In addition to serialization for checkpointing, GPTrees may read and write themselves to streams in three ways.
31 *
32 * <ul>
33 * <li><b>writeTree(...,DataOutput)/readTree(...,DataInput)</b>&nbsp;&nbsp;&nbsp;This method
34 * transmits or receives a GPTree in binary.  It is the most efficient approach to sending
35 * GPTrees over networks, etc.  The default versions of writeTree/readTree call writeRootedTree/readRootedTree
36 * on their respective GPNode roots.
37 *
38 * <li><b>printTree(...,PrintWriter)/readTree(...,LineNumberReader)</b>&nbsp;&nbsp;&nbsp;This
39 * approach transmits or receives a GPTree in text encoded such that the GPTree is largely readable
40 * by humans but can be read back in 100% by ECJ as well.  To do this, these methods will typically encode numbers
41 * using the <tt>ec.util.Code</tt> class.  These methods are mostly used to write out populations to
42 * files for inspection, slight modification, then reading back in later on.  <b>readTree</b>
43 * largely calls readRootedTree on the GPNode root.  Likewise, <b>printTree</b> calls printRootedTree
44 *
45 * <li><b>printTreeForHumans(...,PrintWriter)</b>&nbsp;&nbsp;&nbsp;This
46 * approach prints a GPTree in a fashion intended for human consumption only.
47 * <b>printTreeForHumans</b> calls either <b>makeCTree</b> and prints the result,
48 * calls <b>makeLatexTree</b> and prints the result, or calls <b>printRootedTreeForHumans</b> on the root.
49 * Which one is called depends on the kind of tree you have chosen to print for humans, as is discussed next.
50 * </ul>
51
52
53
54 * <p>GPTrees can print themselves for humans in one of <b>four</b> styles:
55 * <ol><li>A GPTree can print the tree as a Koza-style Lisp s-expression, which is the default. 
56 * <li> A GPTree can print itself in pseudo-C format:
57 *     <ol><li>Terminals can be printed either as variables "a" or as zero-argument functions "a()"
58 *     <li>One-argument nonterminals are printed as functions "a(b)"
59 *     <li>Two-argument nonterminals can be printed either as operators "b a c" or as functions "a(b, c)"
60 *     <li>Nonterminals with more arguments are printed as functions "a(b, c, d, ...)"
61 * </ol>
62 * <li>A GPTree can print the tree AT&amp;T's Graphviz format.  You can snip the code out and save
63 * it as a ".dot" file to render in any Graphviz renderer (for example, use <a href="http://www.pixelglow.com/graphviz/">
64 * this MacOS X front end to the renderer</a>).
65 * <li>A GPTree can print the tree as a LaTeX2e code snippet, which can be inserted
66 * into a LaTeX2e file and will result in a picture of the tree!  Cool, no?
67 * </ol>
68 *
69 * <p>You turn the C-printing feature on with the <b>c</b> parameter, plus certain
70 * optional parameters (<b>c-operators</b>, <b>c-variables</b>) as described below.
71 * You turn the latex-printing <b>latex</b> parameter below.  The C-printing parameter
72 * takes precedence.
73 * <p>
74 * Here's how the latex system works.  To insert the code, you'll need to include the
75 * <tt>epic</tt>,<tt>ecltree</tt>, and probably the <tt>fancybox</tt> packages,
76 * in that order.  You'll also need to define the command <tt>\gpbox</tt>, which
77 * takes one argument (the string name for the GPNode) and draws a box with that
78 * node.  Lastly, you might want to set a few parameters dealing with the
79 * <tt>ecltree</tt> package.
80 *
81 * <p>Here's an example which looks quite good (pardon the double-backslashes
82 * in front of the usepackage statements -- javadoc is freaking out if I put
83 * a single backslash.  So you'll need to remove the extra backslash in order
84 * to try out this example):
85 
86 <p><table width=100% border=0 cellpadding=0 cellspacing=0>
87 <tr><td bgcolor="#DDDDDD"><font size=-1><tt>
88 <pre>
89
90 \documentclass[]{article}
91 \\usepackage{epic}     <b>% required by ecltree and fancybox packages</b>
92 \\usepackage{ecltree}  <b>% to draw the GP trees</b>
93 \\usepackage{fancybox} <b>% required by \Ovalbox</b>
94
95 \begin{document}
96
97 <b>% minimum distance between nodes on the same line</b>
98 \setlength{\GapWidth}{1em}   
99
100 <b>% draw with a thick dashed line, very nice looking</b>
101 \thicklines \drawwith{\dottedline{2}}   
102
103 <b>% draw an oval and center it with the rule.  You may want to fool with the
104 % rule values, though these seem to work quite well for me.  If you make the
105 % rule smaller than the text height, then the GP nodes may not line up with
106 % each other horizontally quite right, so watch out.</b>
107 \newcommand{\gpbox}[1]{\Ovalbox{#1\rule[-.7ex]{0ex}{2.7ex}}}
108               
109 <b>% Here's the tree which the GP system spat out</b>
110 \begin{bundle}{\gpbox{progn3}}\chunk{\begin{bundle}{\gpbox{if-food-ahead}}
111 \chunk{\begin{bundle}{\gpbox{progn3}}\chunk{\gpbox{right}}
112 \chunk{\gpbox{left}}\chunk{\gpbox{move}}\end{bundle}}
113 \chunk{\begin{bundle}{\gpbox{if-food-ahead}}\chunk{\gpbox{move}}
114 \chunk{\gpbox{left}}\end{bundle}}\end{bundle}}\chunk{\begin{bundle}{\gpbox{progn2}}
115 \chunk{\begin{bundle}{\gpbox{progn2}}\chunk{\gpbox{move}}
116 \chunk{\gpbox{move}}\end{bundle}}\chunk{\begin{bundle}{\gpbox{progn2}}
117 \chunk{\gpbox{right}}\chunk{\gpbox{left}}\end{bundle}}\end{bundle}}
118 \chunk{\begin{bundle}{\gpbox{if-food-ahead}}\chunk{\begin{bundle}{\gpbox{if-food-ahead}}
119 \chunk{\gpbox{move}}\chunk{\gpbox{left}}\end{bundle}}
120 \chunk{\begin{bundle}{\gpbox{if-food-ahead}}\chunk{\gpbox{left}}\chunk{\gpbox{right}}
121 \end{bundle}}\end{bundle}}\end{bundle}
122
123 \end{document}
124 </pre></tt></font></td></tr></table>
125
126 <p><b>Parameters</b><br>
127 <table>
128 <tr><td valign=top><i>base</i>.<tt>tc</tt><br>
129 <font size=-1>String</font></td>
130 <td valign=top>(The tree's constraints)</td></tr>
131 <tr><td valign=top><i>base</i>.<tt>print-style</tt><br>
132 <font size=-1>String, one of: c, dot, latex, lisp</td>
133 <td valign=top>(specifies the print style of the tree)</td></tr>
134 <tr><td valign=top><i>base</i>.<tt>c-operators</tt><br>
135 <font size=-1>bool = <tt>true</tt> (default) or <tt>false</tt></td>
136 <td valign=top>(when printing using c, print two-argument functions operators "b a c"?  The alternative is functions "a(b, c)."</td></tr>
137 <tr><td valign=top><i>base</i>.<tt>c-variables</tt><br>
138 <font size=-1>bool = <tt>true</tt> (default) or <tt>false</tt></td>
139 <td valign=top>(when printing using c, print zero-argument functions as variables "a"?  The alternative is functions "a()".)</td></tr>
140 </table>
141
142 <p><b>Default Base</b><br>
143 gp.tree
144
145 * @author Sean Luke
146 * @version 1.0
147 */
148
149public class GPTree implements GPNodeParent, Prototype
150    {
151    public static final String P_TREE = "tree";
152    public static final String P_TREECONSTRAINTS = "tc";
153    public static final String P_USEGRAPHVIZ = "graphviz";
154    public static final String P_USELATEX = "latex";
155    public static final String P_USEC = "c";
156    public static final String P_USEOPS = "c-operators";
157    public static final String P_USEVARS = "c-variables";
158    public static final int NO_TREENUM = -1;
159
160    public static final String P_PRINT_STYLE = "print-style";
161    public static final String V_LISP = "lisp";
162    public static final String V_DOT = "dot";
163    public static final String V_LATEX = "latex";
164    public static final String V_C = "c";
165    public static final int PRINT_STYLE_LISP = 0;
166    public static final int PRINT_STYLE_DOT = 1;
167    public static final int PRINT_STYLE_LATEX = 2;
168    public static final int PRINT_STYLE_C = 3;
169
170
171    /** the root GPNode in the GPTree */
172    public GPNode child;
173
174    /** the owner of the GPTree */
175    public GPIndividual owner;
176
177    /** constraints on the GPTree  -- don't access the constraints through
178        this variable -- use the constraints() method instead, which will give
179        the actual constraints object. */
180    public byte constraints;
181
182    /** The print style of the GPTree. */
183    public int printStyle;
184
185    /** When using c to print for humans, do we print terminals as variables?
186        (as opposed to zero-argument functions)? */
187    public boolean printTerminalsAsVariablesInC;
188
189    /** When using c to print for humans, do we print two-argument nonterminals in operator form "a op b"?
190        (as opposed to functions "op(a, b)")? */
191    public boolean printTwoArgumentNonterminalsAsOperatorsInC;
192
193    public final GPTreeConstraints constraints( final GPInitializer initializer )
194        { return initializer.treeConstraints[constraints]; }
195
196    public Parameter defaultBase()
197        {
198        return GPDefaults.base().push(P_TREE);
199        }
200
201    /** Returns true if I am "genetically" the same as tree,
202        though we may have different owners. */
203    public boolean treeEquals(GPTree tree)
204        {
205        return child.rootedTreeEquals(tree.child);
206        }
207
208    /** Returns a hash code for comparing different GPTrees.  In
209        general, two trees which are treeEquals(...) should have the
210        same hash code. */
211    public int treeHashCode()
212        {
213        return child.rootedTreeHashCode();
214        }
215
216    /** Like clone() but doesn't copy the tree. */
217    public GPTree lightClone()
218        {
219        try
220            {
221            return (GPTree)(super.clone());  // note that the root child reference is copied, not cloned
222            }
223        catch (CloneNotSupportedException e) { throw new InternalError(); } // never happens
224        }
225
226    /** Deep-clones the tree.  Note that you should not deep-clone trees attached to the
227        prototypical GPIndividual: they are blank trees with no root, and this method
228        will generate a NullPointerException as a result. */
229    public Object clone()
230        {
231        GPTree newtree = lightClone();
232        newtree.child = (GPNode)(child.clone());  // force a deep copy
233        newtree.child.parent = newtree;
234        newtree.child.argposition = 0;
235        return newtree;
236        }
237   
238    /** An expensive function which determines my tree number -- only
239        use for errors, etc. Returns ec.gp.GPTree.NO_TREENUM if the
240        tree number could not be
241        determined (might happen if it's not been assigned yet). */
242    public int treeNumber()
243        {
244        if (owner==null) return NO_TREENUM;
245        if (owner.trees==null) return NO_TREENUM;
246        for(int x=0;x<owner.trees.length;x++)
247            if (owner.trees[x]==this) return x;
248        return NO_TREENUM;
249        }
250
251    /** Sets up a prototypical GPTree with those features it shares with
252        other GPTrees in its position in its GPIndividual, and nothhing more.
253
254        This must be called <i>after</i> the GPTypes and GPNodeConstraints
255        have been set up.  Presently they're set up in GPInitializer,
256        which gets called before this does, so we're safe. */
257    public void setup(final EvolutionState state, final Parameter base)
258        {
259        Parameter def = defaultBase();
260
261        // get rid of deprecated values
262        if (state.parameters.exists(base.push(P_USEGRAPHVIZ), def.push(P_USEGRAPHVIZ)))
263            state.output.error("Parameter no longer used.  See GPTree.java for details.", base.push(P_USEGRAPHVIZ), def.push(P_USEGRAPHVIZ));
264        if (state.parameters.exists(base.push(P_USELATEX), def.push(P_USELATEX)))
265            state.output.error("Parameter no longer used.  See GPTree.java for details.", base.push(P_USELATEX), def.push(P_USELATEX));
266        if (state.parameters.exists(base.push(P_USEC), def.push(P_USEC)))
267            state.output.error("Parameter no longer used.  See GPTree.java for details.", base.push(P_USEC), def.push(P_USEC));
268        state.output.exitIfErrors();
269
270        String style = state.parameters.getString(base.push(P_PRINT_STYLE), def.push(P_PRINT_STYLE));
271        if (style == null)  // assume Lisp
272            printStyle = PRINT_STYLE_LISP;
273        else if (style.equals(V_C))
274            printStyle = PRINT_STYLE_C;
275        else if (style.equals(V_DOT))
276            printStyle = PRINT_STYLE_DOT;
277        else if (style.equals(V_LATEX))
278            printStyle = PRINT_STYLE_LATEX;
279
280        // in C, treat terminals as variables?  By default, yes.
281        printTerminalsAsVariablesInC = state.parameters.getBoolean(base.push(P_USEVARS),def.push(P_USEVARS),true);
282
283        // in C, treat two-child functions as operators?  By default, yes.
284        printTwoArgumentNonterminalsAsOperatorsInC = state.parameters.getBoolean(base.push(P_USEOPS),def.push(P_USEOPS),true);
285
286        // determine my constraints -- at this point, the constraints should have been loaded.
287        String s = state.parameters.getString(base.push(P_TREECONSTRAINTS),
288            def.push(P_TREECONSTRAINTS));
289        if (s==null)
290            state.output.fatal("No tree constraints are defined for the GPTree " + base + ".");
291        else
292            constraints = GPTreeConstraints.constraintsFor(s,state).constraintNumber;
293       
294        state.output.exitIfErrors();  // because I promised
295        // we're not loading the nodes at this point
296        }
297
298
299    /** Verification of validity of the tree -- strictly for debugging purposes only */
300    public final void verify(EvolutionState state)
301        {
302        if (!(state.initializer instanceof GPInitializer))
303            { state.output.error("Initializer is not a GPInitializer"); return; }
304           
305        GPInitializer initializer = (GPInitializer)(state.initializer);
306
307        if (child == null)
308            { state.output.error("Null root child of GPTree."); return; }
309        if (owner == null)
310            { state.output.error("Null owner of GPTree."); return; }
311        if (owner.trees == null)
312            { state.output.error("Owner has null trees."); return; }
313        if (treeNumber() == NO_TREENUM)
314            { state.output.error("No Tree Number! I appear to be an orphan GPTree."); return; }
315        if (constraints < 0 || constraints >= initializer.numTreeConstraints)
316            { state.output.error("Preposterous tree constraints (" + constraints + ")"); return; }
317
318        child.verify(state, constraints(initializer).functionset, 0);
319        state.output.exitIfErrors();
320        }
321
322    /** Prints out the tree in single-line fashion suitable for reading
323        in later by computer. O(n).
324        The default version of this method simply calls child's
325        printRootedTree(...) method.
326    */
327
328    public void printTree(final EvolutionState state, final int log)
329        {
330        printTree(state, log, Output.V_VERBOSE);
331        }
332
333    /** Prints out the tree in single-line fashion suitable for reading
334        in later by computer. O(n).
335        The default version of this method simply calls child's
336        printRootedTree(...) method.
337        @deprecated Verbosity no longer has an effect
338    */
339
340    public void printTree(final EvolutionState state, final int log,
341        final int verbosity)
342        {
343        child.printRootedTree(state,log,0);
344        // printRootedTree doesn't print a '\n', so I need to do so here
345        state.output.println("",log);
346        }
347
348    /** Prints out the tree in single-line fashion suitable for reading
349        in later by computer. O(n).
350        The default version of this method simply calls child's
351        printRootedTree(...) method. */
352
353    public void printTree(final EvolutionState state,
354        final PrintWriter writer)
355        {
356        child.printRootedTree(state,writer,0);
357        // printRootedTree doesn't print a '\n', so I need to do so here
358        writer.println();
359        }
360
361    /** Reads in the tree from a form printed by printTree. */
362    public void readTree(final EvolutionState state,
363        final LineNumberReader reader) throws IOException
364        {
365        int linenumber = reader.getLineNumber();
366
367        // the next line will be the child
368        String s = reader.readLine();
369        if (s==null)  // uh oh
370            state.output.fatal("Reading Line " + linenumber + ": " +
371                "No Tree found.");
372        else
373            {
374            GPInitializer initializer = ((GPInitializer)state.initializer);
375            child = GPNode.readRootedTree(linenumber,new DecodeReturn(s),
376                constraints(initializer).treetype,
377                constraints(initializer).functionset,this,0,state);
378            }
379        }
380
381    public void writeTree(final EvolutionState state,
382        final DataOutput dataOutput) throws IOException
383        {
384        GPInitializer initializer = ((GPInitializer)state.initializer);
385        child.writeRootedTree(state,constraints(initializer).treetype, constraints(initializer).functionset, dataOutput);
386        }
387
388    public void readTree(final EvolutionState state,
389        final DataInput dataInput) throws IOException
390        {
391        GPInitializer initializer = ((GPInitializer)state.initializer);
392        child = GPNode.readRootedTree(state,dataInput,constraints(initializer).treetype, constraints(initializer).functionset, this,0);
393        }
394
395
396    /** Prints out the tree in a readable Lisp-like fashion. O(n).
397        The default version of this method simply calls child's
398        printRootedTreeForHumans(...) method. */
399   
400    public void printTreeForHumans(final EvolutionState state, final int log)
401        {               
402        printTreeForHumans(state, log, Output.V_VERBOSE);
403        }
404
405
406    /** Prints out the tree in a readable Lisp-like fashion. O(n).
407        The default version of this method simply calls child's
408        printRootedTreeForHumans(...) method.
409        @deprecated Verbosity no longer has an effect.
410    */
411   
412    public void printTreeForHumans(final EvolutionState state, final int log,
413        final int verbosity)
414        {               
415        if (printStyle==PRINT_STYLE_C) state.output.print(child.makeCTree(true,
416                printTerminalsAsVariablesInC, printTwoArgumentNonterminalsAsOperatorsInC),log);
417        else if (printStyle==PRINT_STYLE_LATEX) state.output.print(child.makeLatexTree(),log);
418        else if (printStyle==PRINT_STYLE_DOT) state.output.print(child.makeGraphvizTree(), log);
419        else child.printRootedTreeForHumans(state,log,0,0);
420        // printRootedTreeForHumans doesn't print a '\n', so I need to do so here
421        state.output.println("",log);
422        }
423
424    /** Builds a new randomly-generated rooted tree and attaches it to the GPTree. */
425
426    public void buildTree(final EvolutionState state, final int thread)
427        {
428        GPInitializer initializer = ((GPInitializer)state.initializer);
429        child = constraints(initializer).init.newRootedTree(state,
430            constraints(initializer).treetype,
431            thread,
432            this,
433            constraints(initializer).functionset,
434            0,
435            GPNodeBuilder.NOSIZEGIVEN);
436        }
437    }
Note: See TracBrowser for help on using the repository browser.