Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/RehangPipeline.java @ 12912

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

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

File size: 10.6 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.breed;
9import ec.*;
10import ec.util.*;
11import ec.gp.*;
12
13/*
14 * RehangPipeline.java
15 *
16 * Created: Wed Dec 15 21:41:30 1999
17 * By: Sean Luke
18 */
19
20/**
21 * RehangPipeline picks a nonterminal node other than the root
22 * and "rehangs" it as
23 * a new root. Imagine if the tree were nodes connected with string.
24 * Grab the new node and pick it up, letting the other nodes hang
25 * underneath it as a new "root".  That's in effect what you're doing.
26 *
27 * <p><b>Important Note</b>: Because it must be free of any constraints
28 * by nature, RehangPipeline does not work with strong typing.  You must
29 * not have more than one type defined in order to use RehangPipeline. 
30 *
31 * <p>RehangPipeline picks a random tree, then picks randomly from
32 * all the nonterminals in the tree other than the root, and rehangs the
33 * chosen nonterminal
34 * as the new root. If its chosen tree has no nonterminals, it repeats
35 * the choose-tree process.  If after <i>tries</i> times
36 * it has failed to find a tree with nonterminals (other than the root),
37 * it gives up and simply
38 * copies the individual.  As you might guess, determining if a tree has
39 * nonterminals is very fast, so <i>tries</i> can be pretty large with
40 * little to no detriment to evolution speed.
41 *
42 * <p>"Rehanging" is complicated to describe.  First, you pick a random
43 * child of your chosen nonterminal <i>n</i>,
44 * and remove this subtree from the tree.
45 * Call this subtree <i>T</i>.  Next, you set the nonterminal as a new root; its
46 * former parent <i>p</i> now fills the slot left behind by the missing subtree.
47 * The <i>p</i>'s former parent <i>q</i> now fills the slot left behind by
48 * <i>n</i>.  <i>q</i>'s former parent <i>r</i> now fills the slot left behind
49 * by <i>p</i>, and so on.  This proceeds all the way up to the old root, which
50 * will be left with one empty slot (where its former child was that is now its new
51 * parent).  This slot is then filled with <i>T</i>
52
53 <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
54 ...as many as the source produces
55
56 <p><b>Number of Sources</b><br>
57 1
58
59 <p><b>Parameters</b><br>
60 <table>
61 <tr><td valign=top><i>base</i>.<tt>tries</tt><br>
62 <font size=-1>int &gt;= 1</font></td>
63 <td valign=top>(number of times to try finding valid pairs of nodes)</td></tr>
64
65 <tr><td valign=top><i>base</i>.<tt>tree.0</tt><br>
66 <font size=-1>0 &lt; int &lt; (num trees in individuals), if exists</font></td>
67 <td valign=top>(tree chosen for mutation; if parameter doesn't exist, tree is picked at random)</td></tr>
68
69 </table>
70
71 <p><b>Default Base</b><br>
72 gp.breed.rehang
73
74
75 * @author Sean Luke
76 * @version 1.0
77 */
78
79public class RehangPipeline extends GPBreedingPipeline
80    {
81    public static final String P_REHANG = "rehang";
82    public static final String P_NUM_TRIES = "tries";
83    public static final int NUM_SOURCES = 1;
84   
85    /** The number of times the pipeline tries to find a tree with a
86        nonterminal before giving up and just copying the individual. */
87    int numTries;
88
89    /** Is our tree fixed?  If not, this is -1 */
90    int tree;
91
92    public Parameter defaultBase() { return GPBreedDefaults.base().push(P_REHANG); }
93
94    public int numSources() { return NUM_SOURCES; }
95
96    public void setup(final EvolutionState state, final Parameter base)
97        {
98        super.setup(state,base);
99       
100        Parameter def = defaultBase();
101
102        numTries = state.parameters.getInt(base.push(P_NUM_TRIES),
103            def.push(P_NUM_TRIES),1);
104        if (numTries == 0)
105            state.output.fatal("RehangPipeline has an invalid number of tries (it must be >= 1).",base.push(P_NUM_TRIES),def.push(P_NUM_TRIES));
106
107        if (((GPInitializer)state.initializer).numAtomicTypes + ((GPInitializer)state.initializer).numSetTypes > 1)
108            state.output.fatal("RehangPipeline only works when there is only one type (the system is typeless", base,def);
109
110        tree = TREE_UNFIXED;
111        if (state.parameters.exists(base.push(P_TREE).push(""+0),
112                def.push(P_TREE).push(""+0)))
113            {
114            tree = state.parameters.getInt(base.push(P_TREE).push(""+0),
115                def.push(P_TREE).push(""+0),0);
116            if (tree==-1)
117                state.output.fatal("Tree fixed value, if defined, must be >= 0");
118            }
119        }
120
121
122
123    private int numRehangableNodes(final GPNode root, int soFar)
124        {
125        // we don't include the tree root
126        for(int x=0;x<root.children.length;x++)
127            soFar = _numRehangableNodes(root.children[x],soFar);
128        return soFar;   
129        }
130
131    private int _numRehangableNodes(final GPNode root, int soFar)
132        {
133        if (root.children.length>0) soFar++;  // rehangable
134        for(int x=0;x<root.children.length;x++)
135            soFar = _numRehangableNodes(root.children[x],soFar);
136        return soFar;
137        }
138
139
140    private GPNode rehangableNode;
141
142    private int pickRehangableNode(final GPNode root, int num)
143        {
144        // we don't include the tree root
145        for(int x=0;x<root.children.length;x++)
146            {
147            num = _pickRehangableNode(root.children[x],num);
148            if (num==-1) break;  // someone found it
149            }   
150        return num;     
151        }
152
153    // sticks the node in
154    private int _pickRehangableNode(final GPNode root, int num)
155        {
156        if (root.children.length>0)  // rehangable
157            {
158            num--;
159            if (num==-1)  // found it
160                {
161                rehangableNode = root;
162                return num;
163                }
164            }
165        for(int x=0;x<root.children.length;x++)
166            {
167            num = _pickRehangableNode(root.children[x],num);
168            if (num==-1) break;  // someone found it
169            }
170        return num;     
171        }
172   
173
174    private void rehang(final EvolutionState state, final int thread,
175        GPNode pivot, final GPNode root)
176        {
177        // pivot must not be root
178        if (pivot==root) // uh oh
179            throw new InternalError("Oops, pivot==root in ec.gp.breed.Rehang.rehang(...)");
180
181        // snip off a random child from the pivot
182        byte spot = (byte)(state.random[thread].nextInt(pivot.children.length));
183        byte newSpot; byte tmpSpot;
184        GPNode cut = pivot.children[spot];
185
186        // rehang pivot as new root and set it up
187        GPNode newPivot = (GPNode)(pivot.parent);       
188        ((GPTree)root.parent).child = pivot;
189        pivot.parent = root.parent;
190        newSpot = pivot.argposition;
191        pivot.argposition = 0;
192        GPNode oldPivot = pivot;
193        pivot = newPivot;
194
195        // rehang the intermediate nodes
196        while(pivot!=root)
197            {
198            newPivot = (GPNode)(pivot.parent);
199           
200            pivot.parent = oldPivot;
201            oldPivot.children[spot] = pivot;       
202            tmpSpot = pivot.argposition;
203            pivot.argposition = spot;
204            spot = newSpot;
205            newSpot = tmpSpot;
206           
207            oldPivot = pivot;
208            pivot = newPivot;
209            }
210
211        // rehang the root and set the cut
212        pivot.parent = oldPivot;
213        oldPivot.children[spot] = pivot;
214        pivot.argposition = spot;
215        cut.parent = pivot;
216        cut.argposition = newSpot;
217        pivot.children[newSpot] = cut;
218        }
219
220
221    public int produce(final int min,
222        final int max,
223        final int start,
224        final int subpopulation,
225        final Individual[] inds,
226        final EvolutionState state,
227        final int thread)
228        {
229        // grab n individuals from our source and stick 'em right into inds.
230        // we'll modify them from there
231        int n= sources[0].produce(min,max,start,subpopulation,inds,state,thread);
232
233
234        // should we bother?
235        if (!state.random[thread].nextBoolean(likelihood))
236            return reproduce(n, start, subpopulation, inds, state, thread, false);  // DON'T produce children from source -- we already did
237
238
239
240        // now let's rehang 'em
241        for(int q=start; q < n+start; q++)
242            {
243            GPIndividual i = (GPIndividual)inds[q];
244           
245            if (tree!=TREE_UNFIXED && (tree<0 || tree >= i.trees.length))
246                // uh oh
247                state.output.fatal("RehangPipeline attempted to fix tree.0 to a value which was out of bounds of the array of the individual's trees.  Check the pipeline's fixed tree values -- they may be negative or greater than the number of trees in an individual");
248
249            GPIndividual j;
250            if (sources[0] instanceof BreedingPipeline)
251                // it's already a copy, so just smash the tree in
252                {
253                j=i;
254                }
255            else // need to copy it
256                {
257                j = (GPIndividual)(i.lightClone());
258               
259                // Fill in various tree information that didn't get filled in there
260                j.trees = new GPTree[i.trees.length];
261               
262                for(int x=0;x<j.trees.length;x++)
263                    {
264                    j.trees[x] = (GPTree)(i.trees[x].lightClone());
265                    j.trees[x].owner = j;
266                    j.trees[x].child = (GPNode)(i.trees[x].child.clone());
267                    j.trees[x].child.parent = j.trees[x];
268                    j.trees[x].child.argposition = 0;
269                    }
270                }
271           
272           
273            for (int x=0;x<numTries;x++)
274                {
275                int t;
276                // pick random tree
277                if (tree==TREE_UNFIXED)
278                    if (i.trees.length>1) t = state.random[thread].nextInt(i.trees.length);
279                    else t = 0;
280                else t = tree;
281               
282                // is the tree rehangable?             
283                if (j.trees[t].child.children.length==0) continue; // uh oh, try again
284                boolean rehangable = false;
285                for(int y=0;y<j.trees[t].child.children.length;y++)
286                    if (j.trees[t].child.children[y].children.length>0) // nonterminal
287                        { rehangable = true; break; }
288                if (!rehangable) continue;  // the root's children are all terminals
289
290                int numrehang = numRehangableNodes(j.trees[t].child,0);
291                pickRehangableNode(j.trees[t].child,
292                    state.random[thread].nextInt(numrehang));
293               
294                rehang(state,thread,rehangableNode,j.trees[t].child);
295
296                j.evaluated = false;
297                }
298
299            // add the new individual, replacing its previous source
300            inds[q] = j;
301            }
302        return n;
303        }
304    }
Note: See TracBrowser for help on using the repository browser.