Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OKBJavaConnector/ECJClient/src/ec/gp/build/PTC2.java @ 9449

Last change on this file since 9449 was 6152, checked in by bfarka, 14 years ago

added ecj and custom statistics to communicate with the okb services #1441

File size: 12.8 KB
Line 
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
8package ec.gp.build;
9import ec.*;
10import ec.gp.*;
11import ec.util.*;
12
13/*
14 * PTC2.java
15 *
16 * Created: Tue Jan 25 21:36:02 2000
17 * By: Sean Luke
18 */
19
20/**
21 * PTC2 implements the "Strongly-typed Probabilistic Tree Creation 2 (PTC2)" algorithm described in
22 *
23 * <p>Luke, Sean. 2000. <i>Issues in Scaling Genetic Programming: Breeding Strategies, Tree Generation, and Code Bloat.</i> Ph.D. Dissertation, Department of Computer Science, University of Maryland, College Park, Maryland.
24 *
25 * <p> ...and also in
26 *
27 * <p>Luke, Sean. 2000. Two fast tree-creation algorithms for genetic programming. In <i>IEEE Transactions on Evolutionary Computation</i> 4:3 (September 2000), 274-283. IEEE.
28 *
29 * <p> Both can be found at <a href="http://www.cs.gmu.edu/~sean/papers/">http://www.cs.gmu.edu/~sean/papers/</a>
30 *
31 * <p> PTC2 requires that your function set to implement PTCFunctionSetForm.  The
32 * provided function set, PTCFunctionSet, does exactly this.
33 *
34 * <p>The Strongly-typed PTC2 algorithm roughly works as follows:
35 * the user provides a requested tree size, and PTC2 attempts to build
36 * a tree of that size or that size plus the maximum arity of a nonterminal
37 * in the function set.  PTC2 works roughly like this:
38 *
39 <ol><li>If the tree size requested is 1, pick a random terminal and return it.
40 <li> Else pick a random nonterminal as the root and put each of its unfilled child positions into the queue <i>Q</i>.
41 <li> Loop until the size of <i>Q</i>, plus the size of the nodes in the tree so far, equals or exceeds the requested tree size:
42 <ol><li>Remove a random position from <i>Q</i>.
43 <li>Fill the position with a random nonterminal <i>n</i>.
44 <li>Put each of </i>n's</i> unfilled child positions into <i>Q</i>.
45 </ol>
46 <li>For each position in <i>Q</i>, fill the position with a randomly-chosen terminal.
47 </ol>
48 *
49 * <p> Generally speaking, PTC2 picks a random position in the horizon of the tree (unfiled child node positions), fills it with a nonterminal, thus extending the horizon, and repeats this until the number of nodes (nonterminals) in the tree, plus the number of unfilled node positions, is >= the requested tree size.  Then the remaining horizon is filled with terminals.
50 *
51 * <p> The user-provided requested tree size is either provided directly to the PTC2 algorithm, or if the size is NOSIZEGIVEN, then PTC2 will pick one at random from the GPNodeBuilder probability distribution system (using either max-depth and min-depth, or using num-sizes).
52 *
53 * <p> PTC2 also has provisions for picking nonterminals with a certain probability over other nonterminals of the same return type (and terminals over other terminals likewise), hence its name.  To change the probability of picking various terminals or nonterminals, you modify your PTCFunctionSetForm function set.
54 *
55 * <p>PTC2 further has a maximum depth, which you should set to some fairly big value.  If your maximum depth is small enough that PTC2 often creates trees which bump up against it, then PTC2 will only generate terminals at that depth position.  If the depth is *really* small, it's possible that this means PTC2 will generate trees smaller than you had requested.
56 *
57 <p><b>Parameters</b><br>
58 <table>
59 <tr><td valign=top><i>base</i>.<tt>max-depth</tt><br>
60 <font size=-1>int &gt;= 1</font></td>
61 <td valign=top>maximum allowable tree depth (usually a big value)</td></tr>
62 </table>
63
64 <p><b>Default Base</b><br>
65 gp.breed.ptc2
66
67 * @author Sean Luke
68 * @version 1.0
69 */
70
71public class PTC2 extends GPNodeBuilder
72    {
73    public static final String P_PTC2 = "ptc2";
74    public static final String P_MAXDEPTH = "max-depth";
75
76    /** The largest maximum tree depth GROW can specify -- should be big. */
77    public int maxDepth;
78   
79    public Parameter defaultBase()
80        {
81        return GPBuildDefaults.base().push(P_PTC2);
82        }
83
84    public void setup(final EvolutionState state, final Parameter base)
85        {
86        super.setup(state,base);
87
88        Parameter def = defaultBase();
89
90        // we use size distributions -- did the user specify any?
91        if (!canPick())
92            state.output.fatal("PTC2 needs a distribution of tree sizes to pick from.  You can do this by either setting a distribution (with " + P_NUMSIZES + ") or with "
93                + P_MINSIZE + " and " + P_MAXSIZE + ".", base, def);
94
95        maxDepth = state.parameters.getInt(base.push(P_MAXDEPTH),
96            def.push(P_MAXDEPTH),1);
97        if (maxDepth < 1)
98            state.output.fatal("Maximum depth must be >= 1",
99                base.push(P_MAXDEPTH),
100                def.push(P_MAXDEPTH));
101        }
102
103    public final static int MIN_QUEUE_SIZE = 32;
104   
105    // these are all initialized in enqueue
106    GPNode[] s_node;
107    int[] s_argpos;
108    int[] s_depth;
109    int s_size;
110
111    private void enqueue(final GPNode n, final int argpos, final int depth)
112        {
113        if (s_node==null)
114            {
115            s_node = new GPNode[MIN_QUEUE_SIZE];
116            s_argpos = new int[MIN_QUEUE_SIZE];
117            s_depth = new int[MIN_QUEUE_SIZE];
118            s_size = 0;
119            }
120        else if (s_size==s_node.length) // need to double them
121            {
122            GPNode[] new_s_node = new GPNode[s_size*2];
123            System.arraycopy(s_node,0,new_s_node,0,s_size);
124            s_node = new_s_node;
125            int[] new_s_argpos = new int[s_size*2];
126            System.arraycopy(s_argpos,0,new_s_argpos,0,s_size);
127            s_argpos = new_s_argpos;
128            int[] new_s_depth = new int[s_size*2];
129            System.arraycopy(s_depth,0,new_s_depth,0,s_size);
130            s_depth = new_s_depth;
131            }
132       
133        // okay, let's boogie!
134        s_node[s_size] = n;
135        s_argpos[s_size] = argpos;
136        s_depth[s_size] = depth;
137        s_size++;
138        }
139
140    GPNode dequeue_node;
141    int dequeue_argpos;
142    int dequeue_depth;
143
144    // stashes in dequeue_*
145    private void randomDequeue(final EvolutionState state, final int thread)
146        {
147        int r = state.random[thread].nextInt(s_size);
148        s_size -= 1;
149        // put items r into spot dequeue_*
150        dequeue_node = s_node[r];
151        dequeue_argpos = s_argpos[r];
152        dequeue_depth = s_depth[r];
153        // put items s_size into spot r
154        s_node[r] = s_node[s_size];
155        s_argpos[r] = s_argpos[s_size];
156        s_depth[r] = s_depth[s_size];
157        }
158
159
160    public GPNode newRootedTree(final EvolutionState state,
161        GPType type,
162        final int thread,
163        final GPNodeParent parent,
164        final GPFunctionSet set,
165        final int argposition,
166        int requestedSize)
167        {
168        // ptc2 can mess up if there are no available terminals for a given type.  If this occurs,
169        // and we find ourselves unable to pick a terminal when we want to do so, we will issue a warning,
170        // and pick a nonterminal, violating the ptc2 size and depth contracts.  This can lead to pathological situations
171        // where the system will continue to go on and on unable to stop because it can't pick a terminal,
172        // resulting in running out of memory or some such.  But there are cases where we'd want to let
173        // this work itself out.
174        boolean triedTerminals = false;
175
176        if (!(set instanceof PTCFunctionSetForm))
177            state.output.fatal("Set " + set.name + " is not of the class ec.gp.build.PTCFunctionSetForm, and so cannot be used with PTC Nodebuilders.");
178
179        PTCFunctionSetForm pset = (PTCFunctionSetForm)set;
180
181        // pick a size from the distribution
182        if (requestedSize==NOSIZEGIVEN)
183            requestedSize =
184                pickSize(state,thread);
185
186        GPNode root;
187
188        int t = type.type;
189        GPNode[] terminals = set.terminals[t];
190        GPNode[] nonterminals = set.nonterminals[t];
191        GPNode[] nodes = set.nodes[t];         
192
193        if (nodes.length == 0)
194            errorAboutNoNodeWithType(type, state);   // total failure
195
196
197
198        // return a terminal
199        if ((   requestedSize==1 ||                                                          // Now pick a terminal if our size is 1
200                warnAboutNonterminal(nonterminals.length==0, type, false, state)) &&         // OR if there are NO nonterminals!
201            (triedTerminals = true) &&                                                       // [first set triedTerminals]
202            terminals.length != 0)                                                           // AND if there are available terminals
203            {
204            root = (GPNode)
205                terminals[RandomChoice.pickFromDistribution(
206                    pset.terminalProbabilities(t),
207                    state.random[thread].nextFloat())].lightClone();
208            root.resetNode(state,thread);  // give ERCs a chance to randomize
209            root.argposition = (byte)argposition;
210            root.parent = parent;
211            }
212        else   // return a nonterminal-rooted tree
213            {
214            if (triedTerminals) warnAboutNoTerminalWithType(type, false, state);        // we tried terminals and we're here because there were none!
215
216            // pick a nonterminal
217            root = (GPNode)
218                nonterminals[RandomChoice.pickFromDistribution(
219                    pset.nonterminalProbabilities(t),
220                    state.random[thread].nextFloat())].lightClone();
221            root.resetNode(state,thread);  // give ERCs a chance to randomize
222            root.argposition = (byte)argposition;
223            root.parent = parent;
224
225            // set the depth, size, and enqueuing, and reset the random dequeue
226           
227            s_size=0;  // pretty critical!
228            int s = 1;
229            GPInitializer initializer = ((GPInitializer)state.initializer);
230            GPType[] childtypes = root.constraints(initializer).childtypes;
231            for(int x=0;x<childtypes.length;x++)
232                enqueue(root,x,1);  /* depth 1 */
233           
234                       
235                       
236                       
237            while(s_size>0)
238                {
239                triedTerminals = false;
240                randomDequeue(state,thread);
241                type = dequeue_node.constraints(initializer).childtypes[dequeue_argpos];
242               
243                int y = type.type;
244                terminals = set.terminals[y];
245                nonterminals = set.nonterminals[y];
246                nodes = set.nodes[y];           
247
248                if (nodes.length == 0)
249                    errorAboutNoNodeWithType(type, state);   // total failure
250
251                // pick a terminal
252                if ((   s_size + s >= requestedSize ||                                        // if we need no more nonterminal nodes
253                        dequeue_depth==maxDepth ||                                            // OR if we're at max depth and must pick a terminal
254                        warnAboutNonterminal(nonterminals.length==0, type, false, state)) &&  // OR if there are NO nonterminals!
255                    (triedTerminals = true) &&                                                // [first set triedTerminals]
256                    terminals.length != 0)                                                    // AND if there are available terminals
257                    {
258                    GPNode n = (GPNode)
259                        terminals[RandomChoice.pickFromDistribution(
260                            pset.terminalProbabilities(y),
261                            state.random[thread].nextFloat())].lightClone();
262                    dequeue_node.children[dequeue_argpos] = n;
263                    n.resetNode(state,thread);  // give ERCs a chance to randomize
264                    n.argposition = (byte)dequeue_argpos;
265                    n.parent = dequeue_node;
266                    }
267               
268                // pick a nonterminal and enqueue its children
269                else
270                    {
271                    if (triedTerminals) warnAboutNoTerminalWithType(type, false, state);       // we tried terminals and we're here because there were none!
272                                                                                       
273                    GPNode n = (GPNode)
274                        nonterminals[RandomChoice.pickFromDistribution(
275                            pset.nonterminalProbabilities(y),
276                            state.random[thread].nextFloat())].lightClone();
277                    dequeue_node.children[dequeue_argpos] = n;
278                    n.resetNode(state,thread);  // give ERCs a chance to randomize
279                    n.argposition = (byte)dequeue_argpos;
280                    n.parent = dequeue_node;
281                   
282                    childtypes = n.constraints(initializer).childtypes;
283                    for(int x=0;x<childtypes.length;x++)
284                        enqueue(n,x,dequeue_depth + 1);
285                    }
286                s++;
287                }
288            }
289
290        return root;
291        }
292
293    }
Note: See TracBrowser for help on using the repository browser.