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.koza; |
---|
9 | import ec.*; |
---|
10 | import ec.gp.*; |
---|
11 | import ec.util.*; |
---|
12 | |
---|
13 | /* |
---|
14 | * KozaBuilder.java |
---|
15 | * |
---|
16 | * Created: Sun Oct 29 22:35:34 EST 2006 |
---|
17 | * By: Sean Luke |
---|
18 | */ |
---|
19 | |
---|
20 | /* |
---|
21 | KozaBuilder is an abstract superclass of three tree builders: GROW, FULL, and RAMPED HALF-AND-HALF, |
---|
22 | all described in I/II. As all three classes specify a minimum and maximum depth, these instance |
---|
23 | variables and setup methods appear here; but they are described in detail in the relevant subclasses |
---|
24 | (GrowBuilder, HalfBuilder, and FullBuilder). |
---|
25 | |
---|
26 | <p><b>Parameters</b><br> |
---|
27 | <table> |
---|
28 | <tr><td valign=top><i>base</i>.<tt>min-depth</tt><br> |
---|
29 | <font size=-1>int >= 1</font></td> |
---|
30 | <td valign=top>(smallest "maximum" depth the builder may use for building a tree. 2 is the default.)</td></tr> |
---|
31 | |
---|
32 | <tr><td valign=top><i>base</i>.<tt>max-depth</tt><br> |
---|
33 | <font size=-1>int >= <i>base</i>.<tt>min-depth</tt></font></td> |
---|
34 | <td valign=top>(largest "maximum" depth the builder may use for building a tree. 6 is the default.)</td></tr> |
---|
35 | </table> |
---|
36 | |
---|
37 | @author Sean Luke |
---|
38 | @version 1.0 |
---|
39 | */ |
---|
40 | |
---|
41 | public abstract class KozaBuilder extends GPNodeBuilder |
---|
42 | { |
---|
43 | public static final String P_MAXDEPTH = "max-depth"; |
---|
44 | public static final String P_MINDEPTH = "min-depth"; |
---|
45 | |
---|
46 | /** The largest maximum tree depth RAMPED HALF-AND-HALF can specify. */ |
---|
47 | public int maxDepth; |
---|
48 | |
---|
49 | /** The smallest maximum tree depth RAMPED HALF-AND-HALF can specify. */ |
---|
50 | public int minDepth; |
---|
51 | |
---|
52 | public void setup(final EvolutionState state, final Parameter base) |
---|
53 | { |
---|
54 | super.setup(state,base); |
---|
55 | |
---|
56 | Parameter def = defaultBase(); |
---|
57 | |
---|
58 | // load maxdepth and mindepth, check that maxdepth>0, mindepth>0, maxdepth>=mindepth |
---|
59 | maxDepth = state.parameters.getInt(base.push(P_MAXDEPTH),def.push(P_MAXDEPTH),1); |
---|
60 | if (maxDepth<=0) |
---|
61 | state.output.fatal("The Max Depth for a KozaBuilder must be at least 1.", |
---|
62 | base.push(P_MAXDEPTH),def.push(P_MAXDEPTH)); |
---|
63 | |
---|
64 | minDepth = state.parameters.getInt(base.push(P_MINDEPTH),def.push(P_MINDEPTH),1); |
---|
65 | if (minDepth<=0) |
---|
66 | state.output.fatal("The Min Depth for a KozaBuilder must be at least 1.", |
---|
67 | base.push(P_MINDEPTH),def.push(P_MINDEPTH)); |
---|
68 | |
---|
69 | if (maxDepth<minDepth) |
---|
70 | state.output.fatal("Max Depth must be >= Min Depth for a KozaBuilder", |
---|
71 | base.push(P_MAXDEPTH),def.push(P_MAXDEPTH)); |
---|
72 | } |
---|
73 | |
---|
74 | /** A private recursive method which builds a FULL-style tree for newRootedTree(...) */ |
---|
75 | protected GPNode fullNode(final EvolutionState state, |
---|
76 | final int current, |
---|
77 | final int max, |
---|
78 | final GPType type, |
---|
79 | final int thread, |
---|
80 | final GPNodeParent parent, |
---|
81 | final int argposition, |
---|
82 | final GPFunctionSet set) |
---|
83 | { |
---|
84 | // fullNode can mess up if there are no available terminals for a given type. If this occurs, |
---|
85 | // and we find ourselves unable to pick a terminal when we want to do so, we will issue a warning, |
---|
86 | // and pick a nonterminal, violating the "FULL" contract. This can lead to pathological situations |
---|
87 | // where the system will continue to go on and on unable to stop because it can't pick a terminal, |
---|
88 | // resulting in running out of memory or some such. But there are cases where we'd want to let |
---|
89 | // this work itself out. |
---|
90 | boolean triedTerminals = false; // did we try -- and fail -- to fetch a terminal? |
---|
91 | |
---|
92 | int t = type.type; |
---|
93 | GPNode[] terminals = set.terminals[t]; |
---|
94 | GPNode[] nonterminals = set.nonterminals[t]; |
---|
95 | GPNode[] nodes = set.nodes[t]; |
---|
96 | |
---|
97 | if (nodes.length == 0) |
---|
98 | errorAboutNoNodeWithType(type, state); // total failure |
---|
99 | |
---|
100 | // pick a terminal when we're at max depth or if there are NO nonterminals |
---|
101 | if (( current+1 >= max || // Now pick if we're at max depth |
---|
102 | warnAboutNonterminal(nonterminals.length==0, type, false, state)) && // OR if there are NO nonterminals! |
---|
103 | (triedTerminals = true) && // [first set triedTerminals] |
---|
104 | terminals.length != 0) // AND if there are available terminals |
---|
105 | { |
---|
106 | GPNode n = (GPNode)(terminals[state.random[thread].nextInt(terminals.length)].lightClone()); |
---|
107 | n.resetNode(state,thread); // give ERCs a chance to randomize |
---|
108 | n.argposition = (byte)argposition; |
---|
109 | n.parent = parent; |
---|
110 | return n; |
---|
111 | } |
---|
112 | |
---|
113 | // else force a nonterminal unless we have no choice |
---|
114 | else |
---|
115 | { |
---|
116 | if (triedTerminals) warnAboutNoTerminalWithType(type, false, state); // we tried terminals and we're here because there were none! |
---|
117 | |
---|
118 | GPNode[] nodesToPick = set.nonterminals[type.type]; |
---|
119 | if (nodesToPick==null || nodesToPick.length ==0) // no nonterminals, hope the guy knows what he's doing! |
---|
120 | nodesToPick = set.terminals[type.type]; // this can only happen with the warning about nonterminals above |
---|
121 | |
---|
122 | GPNode n = (GPNode)(nodesToPick[state.random[thread].nextInt(nodesToPick.length)].lightClone()); |
---|
123 | n.resetNode(state,thread); // give ERCs a chance to randomize |
---|
124 | n.argposition = (byte)argposition; |
---|
125 | n.parent = parent; |
---|
126 | |
---|
127 | // Populate the node... |
---|
128 | GPType[] childtypes = n.constraints(((GPInitializer)state.initializer)).childtypes; |
---|
129 | for(int x=0;x<childtypes.length;x++) |
---|
130 | n.children[x] = fullNode(state,current+1,max,childtypes[x],thread,n,x,set); |
---|
131 | |
---|
132 | return n; |
---|
133 | } |
---|
134 | } |
---|
135 | |
---|
136 | /** A private function which recursively returns a GROW tree to newRootedTree(...) */ |
---|
137 | protected GPNode growNode(final EvolutionState state, |
---|
138 | final int current, |
---|
139 | final int max, |
---|
140 | final GPType type, |
---|
141 | final int thread, |
---|
142 | final GPNodeParent parent, |
---|
143 | final int argposition, |
---|
144 | final GPFunctionSet set) |
---|
145 | { |
---|
146 | // growNode can mess up if there are no available terminals for a given type. If this occurs, |
---|
147 | // and we find ourselves unable to pick a terminal when we want to do so, we will issue a warning, |
---|
148 | // and pick a nonterminal, violating the maximum-depth contract. This can lead to pathological situations |
---|
149 | // where the system will continue to go on and on unable to stop because it can't pick a terminal, |
---|
150 | // resulting in running out of memory or some such. But there are cases where we'd want to let |
---|
151 | // this work itself out. |
---|
152 | boolean triedTerminals = false; |
---|
153 | |
---|
154 | int t = type.type; |
---|
155 | GPNode[] terminals = set.terminals[t]; |
---|
156 | GPNode[] nonterminals = set.nonterminals[t]; |
---|
157 | GPNode[] nodes = set.nodes[t]; |
---|
158 | |
---|
159 | if (nodes.length == 0) |
---|
160 | errorAboutNoNodeWithType(type, state); // total failure |
---|
161 | |
---|
162 | // pick a terminal when we're at max depth or if there are NO nonterminals |
---|
163 | if ((current+1 >= max) && // Now pick if we're at max depth |
---|
164 | (triedTerminals = true) && // [first set triedTerminals] |
---|
165 | terminals.length != 0) // AND if there are available terminals |
---|
166 | { |
---|
167 | GPNode n = (GPNode)(terminals[state.random[thread].nextInt(terminals.length)].lightClone()); |
---|
168 | n.resetNode(state,thread); // give ERCs a chance to randomize |
---|
169 | n.argposition = (byte)argposition; |
---|
170 | n.parent = parent; |
---|
171 | return n; |
---|
172 | } |
---|
173 | |
---|
174 | // else pick a random node |
---|
175 | else |
---|
176 | { |
---|
177 | if (triedTerminals) warnAboutNoTerminalWithType(type, false, state); // we tried terminals and we're here because there were none! |
---|
178 | |
---|
179 | GPNode n = (GPNode)(nodes[state.random[thread].nextInt(nodes.length)].lightClone()); |
---|
180 | n.resetNode(state,thread); // give ERCs a chance to randomize |
---|
181 | n.argposition = (byte)argposition; |
---|
182 | n.parent = parent; |
---|
183 | |
---|
184 | // Populate the node... |
---|
185 | GPType[] childtypes = n.constraints(((GPInitializer)state.initializer)).childtypes; |
---|
186 | for(int x=0;x<childtypes.length;x++) |
---|
187 | n.children[x] = growNode(state,current+1,max,childtypes[x],thread,n,x,set); |
---|
188 | |
---|
189 | return n; |
---|
190 | } |
---|
191 | } |
---|
192 | |
---|
193 | } |
---|