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 | * KozaNodeSelector.java |
---|
15 | * |
---|
16 | * Created: Tue Oct 12 17:21:28 1999 |
---|
17 | * By: Sean Luke |
---|
18 | */ |
---|
19 | |
---|
20 | /** |
---|
21 | * KozaNodeSelector is a GPNodeSelector which picks nodes in trees a-la Koza I, |
---|
22 | * with the addition of having a probability of always picking the root. |
---|
23 | * The method divides the range 0.0...1.0 into four probability areas: |
---|
24 | |
---|
25 | <ul> |
---|
26 | <li>One area specifies that the selector must pick a terminal. |
---|
27 | <li>Another area specifies that the selector must pick a nonterminal (if there is one, else a terminal). |
---|
28 | <li>The third area specifies that the selector pick the root node. |
---|
29 | <li>The fourth area specifies that the selector pick any random node. |
---|
30 | </ul> |
---|
31 | |
---|
32 | * <p>The KozaNodeSelector chooses by probability between these four situations. |
---|
33 | * Then, based on the situation it has picked, it selects either a random |
---|
34 | * terminal, nonterminal, root, or arbitrary node from the tree and returns it. |
---|
35 | * |
---|
36 | * <p>As the selector picks a node, it builds up some statistics information |
---|
37 | * which makes it able to pick a little faster in subsequent passes. Thus |
---|
38 | * if you want to reuse this selector on another tree, you need to call |
---|
39 | * reset() first. |
---|
40 | * |
---|
41 | |
---|
42 | <p><b>Parameters</b><br> |
---|
43 | <table> |
---|
44 | <tr><td valign=top><i>base</i>.<tt>terminals</tt><br> |
---|
45 | <font size=-1>0.0 <= float <= 1.0,<br> |
---|
46 | nonterminals + terminals + root <= 1.0</font></td> |
---|
47 | <td valign=top>(the probability we must pick a terminal)</td></tr> |
---|
48 | |
---|
49 | <tr><td valign=top><i>base</i>.<tt>nonterminals</tt><br> |
---|
50 | <font size=-1>0.0 <= float <= 1.0,<br> |
---|
51 | nonterminals + terminals + root <= 1.0</font></td> |
---|
52 | <td valign=top>(the probability we must pick a nonterminal if possible)</td></tr> |
---|
53 | |
---|
54 | <tr><td valign=top><i>base</i>.<tt>root</tt><br> |
---|
55 | <font size=-1>0.0 <= float <= 1.0,<br> |
---|
56 | nonterminals + terminals + root <= 1.0</font></td> |
---|
57 | <td valign=top>(the probability we must pick the root)</td></tr> |
---|
58 | |
---|
59 | </table> |
---|
60 | |
---|
61 | <p><b>DefaultBase</b><br> |
---|
62 | gp.koza.ns |
---|
63 | |
---|
64 | * @author Sean Luke |
---|
65 | * @version 1.0 |
---|
66 | */ |
---|
67 | |
---|
68 | public class KozaNodeSelector implements GPNodeSelector |
---|
69 | { |
---|
70 | public static final String P_NODESELECTOR = "ns"; |
---|
71 | public static final String P_TERMINAL_PROBABILITY = "terminals"; |
---|
72 | public static final String P_NONTERMINAL_PROBABILITY = "nonterminals"; |
---|
73 | public static final String P_ROOT_PROBABILITY = "root"; |
---|
74 | |
---|
75 | /** The probability the root must be chosen */ |
---|
76 | public float rootProbability; |
---|
77 | |
---|
78 | /** The probability a terminal must be chosen */ |
---|
79 | public float terminalProbability; |
---|
80 | |
---|
81 | /** The probability a nonterminal must be chosen. */ |
---|
82 | public float nonterminalProbability; |
---|
83 | |
---|
84 | /** The number of nonterminals in the tree, -1 if unknown. */ |
---|
85 | public int nonterminals; |
---|
86 | /** The number of terminals in the tree, -1 if unknown. */ |
---|
87 | public int terminals; |
---|
88 | /** The number of nodes in the tree, -1 if unknown. */ |
---|
89 | public int nodes; |
---|
90 | |
---|
91 | /** Used internally to look for a node. This is threadsafe as long as |
---|
92 | an instance of KozaNodeSelector is used by only one thread. */ |
---|
93 | protected GPNodeGatherer gatherer; |
---|
94 | |
---|
95 | public Parameter defaultBase() |
---|
96 | { |
---|
97 | return GPKozaDefaults.base().push(P_NODESELECTOR); |
---|
98 | } |
---|
99 | |
---|
100 | public KozaNodeSelector() |
---|
101 | { |
---|
102 | gatherer = new GPNodeGatherer(); |
---|
103 | reset(); |
---|
104 | } |
---|
105 | |
---|
106 | public Object clone() |
---|
107 | { |
---|
108 | try |
---|
109 | { |
---|
110 | KozaNodeSelector s = (KozaNodeSelector)(super.clone()); |
---|
111 | // allocate a new gatherer, so we're always threadsafe |
---|
112 | s.gatherer = new GPNodeGatherer(); |
---|
113 | s.reset(); |
---|
114 | return s; |
---|
115 | } |
---|
116 | catch (CloneNotSupportedException e) |
---|
117 | { throw new InternalError(); } // never happens |
---|
118 | } |
---|
119 | |
---|
120 | |
---|
121 | |
---|
122 | public void setup(final EvolutionState state, final Parameter base) |
---|
123 | { |
---|
124 | Parameter def = defaultBase(); |
---|
125 | |
---|
126 | terminalProbability = state.parameters.getFloatWithMax( |
---|
127 | base.push(P_TERMINAL_PROBABILITY), |
---|
128 | def.push(P_TERMINAL_PROBABILITY), 0.0, 1.0); |
---|
129 | if (terminalProbability==-1.0) |
---|
130 | state.output.fatal("Invalid terminal probability for KozaNodeSelector ", |
---|
131 | base.push(P_TERMINAL_PROBABILITY), |
---|
132 | def.push(P_TERMINAL_PROBABILITY)); |
---|
133 | |
---|
134 | nonterminalProbability = state.parameters.getFloatWithMax( |
---|
135 | base.push(P_NONTERMINAL_PROBABILITY), |
---|
136 | def.push(P_NONTERMINAL_PROBABILITY),0.0, 1.0); |
---|
137 | if (nonterminalProbability==-1.0) |
---|
138 | state.output.fatal("Invalid nonterminal probability for KozaNodeSelector ", |
---|
139 | base.push(P_NONTERMINAL_PROBABILITY), |
---|
140 | def.push(P_NONTERMINAL_PROBABILITY)); |
---|
141 | |
---|
142 | rootProbability = state.parameters.getFloatWithMax( |
---|
143 | base.push(P_ROOT_PROBABILITY), |
---|
144 | def.push(P_ROOT_PROBABILITY),0.0, 1.0); |
---|
145 | |
---|
146 | if (rootProbability==-1.0) |
---|
147 | state.output.fatal("Invalid root probability for KozaNodeSelector ", |
---|
148 | base.push(P_ROOT_PROBABILITY), |
---|
149 | def.push(P_ROOT_PROBABILITY)); |
---|
150 | |
---|
151 | if (rootProbability+terminalProbability+nonterminalProbability > 1.0f) |
---|
152 | state.output.fatal("The terminal, nonterminal, and root for KozaNodeSelector" + base + " may not sum to more than 1.0. (" + terminalProbability + " " + nonterminalProbability + " " + rootProbability + ")",base); |
---|
153 | |
---|
154 | reset(); |
---|
155 | } |
---|
156 | |
---|
157 | |
---|
158 | public void reset() |
---|
159 | { |
---|
160 | nonterminals = terminals = nodes = -1; |
---|
161 | } |
---|
162 | |
---|
163 | public GPNode pickNode(final EvolutionState s, |
---|
164 | final int subpopulation, |
---|
165 | final int thread, |
---|
166 | final GPIndividual ind, |
---|
167 | final GPTree tree) |
---|
168 | { |
---|
169 | float rnd = s.random[thread].nextFloat(); |
---|
170 | |
---|
171 | if (rnd > nonterminalProbability + terminalProbability + rootProbability) // pick anyone |
---|
172 | { |
---|
173 | if (nodes==-1) nodes= |
---|
174 | tree.child.numNodes(GPNode.NODESEARCH_ALL); |
---|
175 | { |
---|
176 | tree.child.nodeInPosition(s.random[thread].nextInt(nodes), |
---|
177 | gatherer, |
---|
178 | GPNode.NODESEARCH_ALL); |
---|
179 | return gatherer.node; |
---|
180 | } |
---|
181 | } |
---|
182 | else if (rnd > nonterminalProbability + terminalProbability) // pick the root |
---|
183 | { |
---|
184 | return tree.child; |
---|
185 | } |
---|
186 | else if (rnd > nonterminalProbability) // pick terminals |
---|
187 | { |
---|
188 | if (terminals==-1) terminals = |
---|
189 | tree.child.numNodes(GPNode.NODESEARCH_TERMINALS); |
---|
190 | |
---|
191 | tree.child.nodeInPosition(s.random[thread].nextInt(terminals), |
---|
192 | gatherer, |
---|
193 | GPNode.NODESEARCH_TERMINALS); |
---|
194 | return gatherer.node; |
---|
195 | } |
---|
196 | else // pick nonterminals if you can |
---|
197 | { |
---|
198 | if (nonterminals==-1) |
---|
199 | nonterminals = tree.child.numNodes(GPNode.NODESEARCH_NONTERMINALS); |
---|
200 | if (nonterminals > 0) // there are some nonterminals |
---|
201 | { |
---|
202 | tree.child.nodeInPosition(s.random[thread].nextInt(nonterminals), |
---|
203 | gatherer, |
---|
204 | GPNode.NODESEARCH_NONTERMINALS); |
---|
205 | return gatherer.node; |
---|
206 | } |
---|
207 | else // there ARE no nonterminals! It must be the root node |
---|
208 | { |
---|
209 | return tree.child; |
---|
210 | } |
---|
211 | } |
---|
212 | } |
---|
213 | } |
---|