All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ec.gp.GPTree Maven / Gradle / Ivy

Go to download

ECJ, A Java-based Evolutionary Computation Research System. ECJ is a research EC system written in Java. It was designed to be highly flexible, with nearly all classes (and all of their settings) dynamically determined at runtime by a user-provided parameter file. All structures in the system are arranged to be easily modifiable. Even so, the system was designed with an eye toward efficiency. ECJ is developed at George Mason University's ECLab Evolutionary Computation Laboratory. The software has nothing to do with its initials' namesake, Evolutionary Computation Journal. ECJ's sister project is MASON, a multi-agent simulation system which dovetails with ECJ nicely.

The newest version!
/*
  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.*;
import java.io.*;

/* 
 * GPTree.java
 * 
 * Created: Fri Aug 27 17:14:02 1999
 * By: Sean Luke
 */

/**
 * GPTree is a GPNodeParent which holds the root GPNode of a tree
 * of GPNodes.  GPTrees typically fill out an array held in a GPIndividual
 * (their "owner") and their roots are evaluated to evaluate a Genetic
 * programming tree.
 *
 * GPTrees also have constraints, which are shared, and define items
 * shared among several GPTrees.

 * 

In addition to serialization for checkpointing, GPTrees may read and write themselves to streams in three ways. * *

    *
  • writeTree(...,DataOutput)/readTree(...,DataInput)   This method * transmits or receives a GPTree in binary. It is the most efficient approach to sending * GPTrees over networks, etc. The default versions of writeTree/readTree call writeRootedTree/readRootedTree * on their respective GPNode roots. * *
  • printTree(...,PrintWriter)/readTree(...,LineNumberReader)   This * approach transmits or receives a GPTree in text encoded such that the GPTree is largely readable * by humans but can be read back in 100% by ECJ as well. To do this, these methods will typically encode numbers * using the ec.util.Code class. These methods are mostly used to write out populations to * files for inspection, slight modification, then reading back in later on. readTree * largely calls readRootedTree on the GPNode root. Likewise, printTree calls printRootedTree * *
  • printTreeForHumans(...,PrintWriter)   This * approach prints a GPTree in a fashion intended for human consumption only. * printTreeForHumans calls either makeCTree and prints the result, * calls makeLatexTree and prints the result, or calls printRootedTreeForHumans on the root. * Which one is called depends on the kind of tree you have chosen to print for humans, as is discussed next. *
*

GPTrees can print themselves for humans in one of four styles: *

  1. A GPTree can print the tree as a Koza-style Lisp s-expression, which is the default. *
  2. A GPTree can print itself in pseudo-C format: *
    1. Terminals can be printed either as variables "a" or as zero-argument functions "a()" *
    2. One-argument nonterminals are printed as functions "a(b)" *
    3. Two-argument nonterminals can be printed either as operators "b a c" or as functions "a(b, c)" *
    4. Nonterminals with more arguments are printed as functions "a(b, c, d, ...)" *
    *
  3. A GPTree can print the tree AT&T's Graphviz format. You can snip the code out and save * it as a ".dot" file to render in any Graphviz renderer (for example, use * this MacOS X front end to the renderer). *
  4. A GPTree can print the tree as a LaTeX2e code snippet, which can be inserted * into a LaTeX2e file and will result in a picture of the tree! Cool, no? *
* *

You turn the C-printing feature on with the c parameter, plus certain * optional parameters (c-operators, c-variables) as described below. * You turn the latex-printing latex parameter below. The C-printing parameter * takes precedence. *

* Here's how the latex system works. To insert the code, you'll need to include the * epic,ecltree, and probably the fancybox packages, * in that order. You'll also need to define the command \gpbox, which * takes one argument (the string name for the GPNode) and draws a box with that * node. Lastly, you might want to set a few parameters dealing with the * ecltree package. * *

Here's an example which looks quite good (pardon the double-backslashes * in front of the usepackage statements -- javadoc is freaking out if I put * a single backslash. So you'll need to remove the extra backslash in order * to try out this example):


 \documentclass[]{article}
 \\usepackage{epic}     % required by ecltree and fancybox packages
 \\usepackage{ecltree}  % to draw the GP trees
 \\usepackage{fancybox} % required by \Ovalbox

 \begin{document}

 % minimum distance between nodes on the same line
 \setlength{\GapWidth}{1em}    

 % draw with a thick dashed line, very nice looking
 \thicklines \drawwith{\dottedline{2}}   

 % draw an oval and center it with the rule.  You may want to fool with the
 % rule values, though these seem to work quite well for me.  If you make the
 % rule smaller than the text height, then the GP nodes may not line up with
 % each other horizontally quite right, so watch out.
 \newcommand{\gpbox}[1]{\Ovalbox{#1\rule[-.7ex]{0ex}{2.7ex}}}
                
 % Here's the tree which the GP system spat out
 \begin{bundle}{\gpbox{progn3}}\chunk{\begin{bundle}{\gpbox{if-food-ahead}}
 \chunk{\begin{bundle}{\gpbox{progn3}}\chunk{\gpbox{right}}
 \chunk{\gpbox{left}}\chunk{\gpbox{move}}\end{bundle}}
 \chunk{\begin{bundle}{\gpbox{if-food-ahead}}\chunk{\gpbox{move}}
 \chunk{\gpbox{left}}\end{bundle}}\end{bundle}}\chunk{\begin{bundle}{\gpbox{progn2}}
 \chunk{\begin{bundle}{\gpbox{progn2}}\chunk{\gpbox{move}}
 \chunk{\gpbox{move}}\end{bundle}}\chunk{\begin{bundle}{\gpbox{progn2}}
 \chunk{\gpbox{right}}\chunk{\gpbox{left}}\end{bundle}}\end{bundle}}
 \chunk{\begin{bundle}{\gpbox{if-food-ahead}}\chunk{\begin{bundle}{\gpbox{if-food-ahead}}
 \chunk{\gpbox{move}}\chunk{\gpbox{left}}\end{bundle}}
 \chunk{\begin{bundle}{\gpbox{if-food-ahead}}\chunk{\gpbox{left}}\chunk{\gpbox{right}}
 \end{bundle}}\end{bundle}}\end{bundle}

 \end{document}
 

Parameters

base.tc
String
(The tree's constraints)
base.print-style
String, one of: c, dot, latex, lisp
(specifies the print style of the tree)
base.c-operators
bool = true (default) or false
(when printing using c, print two-argument functions operators "b a c"? The alternative is functions "a(b, c)."
base.c-variables
bool = true (default) or false
(when printing using c, print zero-argument functions as variables "a"? The alternative is functions "a()".)

Default Base
gp.tree * @author Sean Luke * @version 1.0 */ public class GPTree implements GPNodeParent, Prototype { public static final String P_TREE = "tree"; public static final String P_TREECONSTRAINTS = "tc"; public static final String P_USEGRAPHVIZ = "graphviz"; public static final String P_USELATEX = "latex"; public static final String P_USEC = "c"; public static final String P_USEOPS = "c-operators"; public static final String P_USEVARS = "c-variables"; public static final int NO_TREENUM = -1; public static final String P_PRINT_STYLE = "print-style"; public static final String V_LISP = "lisp"; public static final String V_DOT = "dot"; public static final String V_LATEX = "latex"; public static final String V_C = "c"; public static final int PRINT_STYLE_LISP = 0; public static final int PRINT_STYLE_DOT = 1; public static final int PRINT_STYLE_LATEX = 2; public static final int PRINT_STYLE_C = 3; /** the root GPNode in the GPTree */ public GPNode child; /** the owner of the GPTree */ public GPIndividual owner; /** constraints on the GPTree -- don't access the constraints through this variable -- use the constraints() method instead, which will give the actual constraints object. */ public byte constraints; /** The print style of the GPTree. */ public int printStyle; /** When using c to print for humans, do we print terminals as variables? (as opposed to zero-argument functions)? */ public boolean printTerminalsAsVariablesInC; /** When using c to print for humans, do we print two-argument nonterminals in operator form "a op b"? (as opposed to functions "op(a, b)")? */ public boolean printTwoArgumentNonterminalsAsOperatorsInC; public final GPTreeConstraints constraints( final GPInitializer initializer ) { return initializer.treeConstraints[constraints]; } public Parameter defaultBase() { return GPDefaults.base().push(P_TREE); } /** Returns true if I am "genetically" the same as tree, though we may have different owners. */ public boolean treeEquals(GPTree tree) { return child.rootedTreeEquals(tree.child); } /** Returns a hash code for comparing different GPTrees. In general, two trees which are treeEquals(...) should have the same hash code. */ public int treeHashCode() { return child.rootedTreeHashCode(); } /** Like clone() but doesn't copy the tree. */ public GPTree lightClone() { try { return (GPTree)(super.clone()); // note that the root child reference is copied, not cloned } catch (CloneNotSupportedException e) { throw new InternalError(); } // never happens } /** Deep-clones the tree. Note that you should not deep-clone trees attached to the prototypical GPIndividual: they are blank trees with no root, and this method will generate a NullPointerException as a result. */ public Object clone() { GPTree newtree = lightClone(); newtree.child = (GPNode)(child.clone()); // force a deep copy newtree.child.parent = newtree; newtree.child.argposition = 0; return newtree; } /** An expensive function which determines my tree number -- only use for errors, etc. Returns ec.gp.GPTree.NO_TREENUM if the tree number could not be determined (might happen if it's not been assigned yet). */ public int treeNumber() { if (owner==null) return NO_TREENUM; if (owner.trees==null) return NO_TREENUM; for(int x=0;xafter the GPTypes and GPNodeConstraints have been set up. Presently they're set up in GPInitializer, which gets called before this does, so we're safe. */ public void setup(final EvolutionState state, final Parameter base) { Parameter def = defaultBase(); // get rid of deprecated values if (state.parameters.exists(base.push(P_USEGRAPHVIZ), def.push(P_USEGRAPHVIZ))) state.output.error("Parameter no longer used. See GPTree.java for details.", base.push(P_USEGRAPHVIZ), def.push(P_USEGRAPHVIZ)); if (state.parameters.exists(base.push(P_USELATEX), def.push(P_USELATEX))) state.output.error("Parameter no longer used. See GPTree.java for details.", base.push(P_USELATEX), def.push(P_USELATEX)); if (state.parameters.exists(base.push(P_USEC), def.push(P_USEC))) state.output.error("Parameter no longer used. See GPTree.java for details.", base.push(P_USEC), def.push(P_USEC)); state.output.exitIfErrors(); String style = state.parameters.getString(base.push(P_PRINT_STYLE), def.push(P_PRINT_STYLE)); if (style == null) // assume Lisp printStyle = PRINT_STYLE_LISP; else if (style.equals(V_C)) printStyle = PRINT_STYLE_C; else if (style.equals(V_DOT)) printStyle = PRINT_STYLE_DOT; else if (style.equals(V_LATEX)) printStyle = PRINT_STYLE_LATEX; // in C, treat terminals as variables? By default, yes. printTerminalsAsVariablesInC = state.parameters.getBoolean(base.push(P_USEVARS),def.push(P_USEVARS),true); // in C, treat two-child functions as operators? By default, yes. printTwoArgumentNonterminalsAsOperatorsInC = state.parameters.getBoolean(base.push(P_USEOPS),def.push(P_USEOPS),true); // determine my constraints -- at this point, the constraints should have been loaded. String s = state.parameters.getString(base.push(P_TREECONSTRAINTS), def.push(P_TREECONSTRAINTS)); if (s==null) state.output.fatal("No tree constraints are defined for the GPTree " + base + "."); else constraints = GPTreeConstraints.constraintsFor(s,state).constraintNumber; state.output.exitIfErrors(); // because I promised // we're not loading the nodes at this point } /** Verification of validity of the tree -- strictly for debugging purposes only */ public final void verify(EvolutionState state) { if (!(state.initializer instanceof GPInitializer)) { state.output.error("Initializer is not a GPInitializer"); return; } GPInitializer initializer = (GPInitializer)(state.initializer); if (child == null) { state.output.error("Null root child of GPTree."); return; } if (owner == null) { state.output.error("Null owner of GPTree."); return; } if (owner.trees == null) { state.output.error("Owner has null trees."); return; } if (treeNumber() == NO_TREENUM) { state.output.error("No Tree Number! I appear to be an orphan GPTree."); return; } if (constraints < 0 || constraints >= initializer.numTreeConstraints) { state.output.error("Preposterous tree constraints (" + constraints + ")"); return; } child.verify(state, constraints(initializer).functionset, 0); state.output.exitIfErrors(); } /** Prints out the tree in single-line fashion suitable for reading in later by computer. O(n). The default version of this method simply calls child's printRootedTree(...) method. */ public void printTree(final EvolutionState state, final int log) { printTree(state, log, Output.V_VERBOSE); } /** Prints out the tree in single-line fashion suitable for reading in later by computer. O(n). The default version of this method simply calls child's printRootedTree(...) method. @deprecated Verbosity no longer has an effect */ public void printTree(final EvolutionState state, final int log, final int verbosity) { child.printRootedTree(state,log,0); // printRootedTree doesn't print a '\n', so I need to do so here state.output.println("",log); } /** Prints out the tree in single-line fashion suitable for reading in later by computer. O(n). The default version of this method simply calls child's printRootedTree(...) method. */ public void printTree(final EvolutionState state, final PrintWriter writer) { child.printRootedTree(state,writer,0); // printRootedTree doesn't print a '\n', so I need to do so here writer.println(); } /** Reads in the tree from a form printed by printTree. */ public void readTree(final EvolutionState state, final LineNumberReader reader) throws IOException { int linenumber = reader.getLineNumber(); // the next line will be the child String s = reader.readLine(); if (s==null) // uh oh state.output.fatal("Reading Line " + linenumber + ": " + "No Tree found."); else { GPInitializer initializer = ((GPInitializer)state.initializer); child = GPNode.readRootedTree(linenumber,new DecodeReturn(s), constraints(initializer).treetype, constraints(initializer).functionset,this,0,state); } } public void writeTree(final EvolutionState state, final DataOutput dataOutput) throws IOException { GPInitializer initializer = ((GPInitializer)state.initializer); child.writeRootedTree(state,constraints(initializer).treetype, constraints(initializer).functionset, dataOutput); } public void readTree(final EvolutionState state, final DataInput dataInput) throws IOException { GPInitializer initializer = ((GPInitializer)state.initializer); child = GPNode.readRootedTree(state,dataInput,constraints(initializer).treetype, constraints(initializer).functionset, this,0); } /** Prints out the tree in a readable Lisp-like fashion. O(n). The default version of this method simply calls child's printRootedTreeForHumans(...) method. */ public void printTreeForHumans(final EvolutionState state, final int log) { printTreeForHumans(state, log, Output.V_VERBOSE); } /** Prints out the tree in a readable Lisp-like fashion. O(n). The default version of this method simply calls child's printRootedTreeForHumans(...) method. @deprecated Verbosity no longer has an effect. */ public void printTreeForHumans(final EvolutionState state, final int log, final int verbosity) { if (printStyle==PRINT_STYLE_C) state.output.print(child.makeCTree(true, printTerminalsAsVariablesInC, printTwoArgumentNonterminalsAsOperatorsInC),log); else if (printStyle==PRINT_STYLE_LATEX) state.output.print(child.makeLatexTree(),log); else if (printStyle==PRINT_STYLE_DOT) state.output.print(child.makeGraphvizTree(), log); else child.printRootedTreeForHumans(state,log,0,0); // printRootedTreeForHumans doesn't print a '\n', so I need to do so here state.output.println("",log); } /** Builds a new randomly-generated rooted tree and attaches it to the GPTree. */ public void buildTree(final EvolutionState state, final int thread) { GPInitializer initializer = ((GPInitializer)state.initializer); child = constraints(initializer).init.newRootedTree(state, constraints(initializer).treetype, thread, this, constraints(initializer).functionset, 0, GPNodeBuilder.NOSIZEGIVEN); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy