[6152] | 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 | package ec.gp; |
---|
| 9 | import ec.*; |
---|
| 10 | import ec.util.*; |
---|
| 11 | import java.util.*; |
---|
| 12 | import java.util.Enumeration; |
---|
| 13 | |
---|
| 14 | /* |
---|
| 15 | * GPTreeConstraints.java |
---|
| 16 | * |
---|
| 17 | * Created: Thu Oct 7 15:38:45 1999 |
---|
| 18 | * By: Sean Luke |
---|
| 19 | */ |
---|
| 20 | |
---|
| 21 | /** |
---|
| 22 | * A GPTreeConstraints is a Clique which defines constraint information |
---|
| 23 | * common to many different GPTree trees, namely the tree type, |
---|
| 24 | * builder, and function set. GPTreeConstraints have unique names |
---|
| 25 | * by which they are identified. |
---|
| 26 | * |
---|
| 27 | * <p>In adding new things to GPTreeConstraints, you should ask yourself |
---|
| 28 | * the following questions: first, is this something that takes up too |
---|
| 29 | * much memory to store in GPTrees themseves? second, is this something |
---|
| 30 | * that needs to be accessed very rapidly, so cannot be implemented as |
---|
| 31 | * a method call in a GPTree? third, can this be shared among different |
---|
| 32 | * GPTrees? |
---|
| 33 | * |
---|
| 34 | |
---|
| 35 | <p><b>Parameters</b><br> |
---|
| 36 | <table> |
---|
| 37 | <tr><td valign=top><i>base</i>.<tt>size</tt><br> |
---|
| 38 | <font size=-1>int >= 1</font></td> |
---|
| 39 | <td valign=top>(number of tree constraints)</td></tr> |
---|
| 40 | |
---|
| 41 | <tr><td valign=top><i>base.n</i>.<tt>name</tt><br> |
---|
| 42 | <font size=-1>String</font></td> |
---|
| 43 | <td valign=top>(name of tree constraint <i>n</i>)</td></tr> |
---|
| 44 | |
---|
| 45 | <tr><td valign=top><i>base.n</i>.<tt>init</tt><br> |
---|
| 46 | <font size=-1>classname, inherits and != ec.gp.GPNodeBuilder</font></td> |
---|
| 47 | <td valign=top>(GP node builder for tree constraint <i>n</i>)</td></tr> |
---|
| 48 | |
---|
| 49 | <tr><td valign=top><i>base.n</i>.<tt>returns</tt><br> |
---|
| 50 | <font size=-1>String</font></td> |
---|
| 51 | <td valign=top>(tree type for tree constraint <i>n</i>)</td></tr> |
---|
| 52 | |
---|
| 53 | <tr><td valign=top><i>base.n</i>.<tt>fset</tt><br> |
---|
| 54 | <font size=-1>String</font></td> |
---|
| 55 | <td valign=top>(function set for tree constraint <i>n</i>)</td></tr> |
---|
| 56 | |
---|
| 57 | </table> |
---|
| 58 | |
---|
| 59 | |
---|
| 60 | * @author Sean Luke |
---|
| 61 | * @version 1.0 |
---|
| 62 | */ |
---|
| 63 | |
---|
| 64 | public class GPTreeConstraints implements Clique |
---|
| 65 | { |
---|
| 66 | public static final int SIZE_OF_BYTE = 256; |
---|
| 67 | public final static String P_NAME = "name"; |
---|
| 68 | public final static String P_SIZE = "size"; |
---|
| 69 | public final static String P_INIT = "init"; |
---|
| 70 | public static final String P_RETURNS = "returns"; |
---|
| 71 | public static final String P_FUNCTIONSET = "fset"; |
---|
| 72 | |
---|
| 73 | public String name; |
---|
| 74 | |
---|
| 75 | /** The byte value of the constraints -- we can only have 256 of them */ |
---|
| 76 | public byte constraintNumber; |
---|
| 77 | |
---|
| 78 | /** The builder for the tree */ |
---|
| 79 | public GPNodeBuilder init; |
---|
| 80 | |
---|
| 81 | /** The type of the root of the tree */ |
---|
| 82 | public GPType treetype; |
---|
| 83 | |
---|
| 84 | /** The function set for nodes in the tree */ |
---|
| 85 | public GPFunctionSet functionset; |
---|
| 86 | |
---|
| 87 | public String toString() { return name; } |
---|
| 88 | |
---|
| 89 | /** This must be called <i>after</i> the GPTypes and GPFunctionSets |
---|
| 90 | have been set up. */ |
---|
| 91 | public final void setup(final EvolutionState state, final Parameter base) |
---|
| 92 | { |
---|
| 93 | // What's my name? |
---|
| 94 | name = state.parameters.getString(base.push(P_NAME),null); |
---|
| 95 | if (name==null) |
---|
| 96 | state.output.fatal("No name was given for this function set.", |
---|
| 97 | base.push(P_NAME)); |
---|
| 98 | |
---|
| 99 | // Register me |
---|
| 100 | GPTreeConstraints old_constraints = |
---|
| 101 | (GPTreeConstraints)(((GPInitializer)state.initializer).treeConstraintRepository.put(name,this)); |
---|
| 102 | if (old_constraints != null) |
---|
| 103 | state.output.fatal("The GP tree constraint \"" + name + "\" has been defined multiple times.", base.push(P_NAME)); |
---|
| 104 | |
---|
| 105 | // Load my initializing builder |
---|
| 106 | init = (GPNodeBuilder)(state.parameters.getInstanceForParameter(base.push(P_INIT),null,GPNodeBuilder.class)); |
---|
| 107 | init.setup(state,base.push(P_INIT)); |
---|
| 108 | |
---|
| 109 | // Load my return type |
---|
| 110 | String s = state.parameters.getString(base.push(P_RETURNS),null); |
---|
| 111 | if (s==null) |
---|
| 112 | state.output.fatal("No return type given for the GPTreeConstraints " + name, base.push(P_RETURNS)); |
---|
| 113 | treetype = GPType.typeFor(s,state); |
---|
| 114 | |
---|
| 115 | // Load my function set |
---|
| 116 | |
---|
| 117 | s = state.parameters.getString(base.push(P_FUNCTIONSET),null); |
---|
| 118 | if (s==null) |
---|
| 119 | state.output.fatal("No function set given for the GPTreeConstraints " + name, base.push(P_RETURNS)); |
---|
| 120 | functionset = GPFunctionSet.functionSetFor(s,state); |
---|
| 121 | state.output.exitIfErrors(); // otherwise checkFunctionSetValidity might crash below |
---|
| 122 | |
---|
| 123 | // Determine the validity of the function set |
---|
| 124 | // the way we do that is by gathering all the types that |
---|
| 125 | // are transitively used, starting with treetype, as in: |
---|
| 126 | Hashtable typ = new Hashtable(); |
---|
| 127 | checkFunctionSetValidity(state, typ, treetype); |
---|
| 128 | // next we make sure that for every one of these types, |
---|
| 129 | // there's a terminal with that return type, and *maybe* |
---|
| 130 | // a nonterminal |
---|
| 131 | Enumeration e = typ.elements(); |
---|
| 132 | while (e.hasMoreElements()) |
---|
| 133 | { |
---|
| 134 | GPType t = (GPType)(e.nextElement()); |
---|
| 135 | GPNode[] i = functionset.nodes[t.type]; |
---|
| 136 | if (i.length==0) // yeesh |
---|
| 137 | state.output.error("In function set " + functionset + " for the GPTreeConstraints " + this + ", no nodes at all are given with the return type " + t + " which is required by other functions in the function set or by the tree's return type. This almost certainly indicates a serious typing error.", base); |
---|
| 138 | else |
---|
| 139 | { |
---|
| 140 | i = functionset.terminals[t.type]; |
---|
| 141 | if (i.length==0) // uh oh |
---|
| 142 | state.output.warning("In function set " + functionset + " for the GPTreeConstraints " + this + ", no terminals are given with the return type " + t + " which is required by other functions in the function set or by the tree's return type. Nearly all tree-builders in ECJ require the ability to add a terminal of any type for which there is a nonterminal, and at any time. Without terminals, your code may not work. One common indication that a tree-builder has failed due to this problem is if you get the MersenneTwister error 'n must be positive'.", base); |
---|
| 143 | i = functionset.nonterminals[t.type]; |
---|
| 144 | if (i.length==0) // uh oh |
---|
| 145 | state.output.warning("In function set " + functionset + " for the GPTreeConstraints " + this + ", no *nonterminals* are given with the return type " + t + " which is required by other functions in the function set or by the tree's return type. This may or may not be a problem for you.", base); |
---|
| 146 | } |
---|
| 147 | } |
---|
| 148 | state.output.exitIfErrors(); |
---|
| 149 | } |
---|
| 150 | |
---|
| 151 | // When completed, done will hold all the types which are needed |
---|
| 152 | // in the function set -- you can then check to make sure that |
---|
| 153 | // they contain at least one terminal and (hopefully) at least |
---|
| 154 | // one nonterminal. |
---|
| 155 | |
---|
| 156 | private void checkFunctionSetValidity(final EvolutionState state, |
---|
| 157 | final Hashtable done, |
---|
| 158 | final GPType type) |
---|
| 159 | { |
---|
| 160 | // put type in the hashtable -- it's being used |
---|
| 161 | done.put(type,type); |
---|
| 162 | |
---|
| 163 | // Grab the array in nodes |
---|
| 164 | GPNode[] i = functionset.nodes[type.type]; |
---|
| 165 | |
---|
| 166 | // For each argument type in a node in i, if it's not in done, |
---|
| 167 | // then add it to done and call me on it |
---|
| 168 | GPInitializer initializer = ((GPInitializer)state.initializer); |
---|
| 169 | for (int x=0; x<i.length;x++) |
---|
| 170 | for (int y=0;y<i[x].constraints(initializer).childtypes.length;y++) |
---|
| 171 | if (done.get(i[x].constraints(initializer).childtypes[y])==null) |
---|
| 172 | { |
---|
| 173 | checkFunctionSetValidity( |
---|
| 174 | state, done, i[x].constraints(initializer).childtypes[y]); |
---|
| 175 | } |
---|
| 176 | } |
---|
| 177 | |
---|
| 178 | |
---|
| 179 | |
---|
| 180 | /** You must guarantee that after calling constraintsFor(...) one or |
---|
| 181 | several times, you call state.output.exitIfErrors() once. */ |
---|
| 182 | |
---|
| 183 | public static GPTreeConstraints constraintsFor(final String constraintsName, |
---|
| 184 | final EvolutionState state) |
---|
| 185 | { |
---|
| 186 | GPTreeConstraints myConstraints = (GPTreeConstraints)(((GPInitializer)state.initializer).treeConstraintRepository.get(constraintsName)); |
---|
| 187 | if (myConstraints==null) |
---|
| 188 | state.output.error("The GP tree constraint \"" + constraintsName + "\" could not be found."); |
---|
| 189 | return myConstraints; |
---|
| 190 | } |
---|
| 191 | } |
---|