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 | } |
---|