Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OKBJavaConnector/ECJClient/src/ec/gp/breed/MutateSwapPipeline.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.1 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 * MutateSwapPipeline.java
15 *
16 * Created: Wed Dec 15 21:41:30 1999
17 * By: Sean Luke
18 */
19
20/**
21 * MutateSwapPipeline works very similarly to the Swap algorithm
22 * described in  Kumar Chellapilla,
23 * "A Preliminary Investigation into Evolving Modular Programs without Subtree
24 * Crossover", GP98.
25 *
26 * <p>MutateSwapPipeline picks a random tree, then picks
27 * randomly from all the swappable nodes in the tree, and swaps two of its subtrees. 
28 * If its chosen tree has no swappable nodes, it repeats
29 * the choose-tree process.  If after <i>tries</i> times
30 * it has failed to find a tree with swappable nodes, it gives up and simply
31 * copies the individual.
32 *
33 * <p>"Swapping" means to take a node <i>n</i>, and choose two children
34 * nodes of <i>n</i>, <i>x</i> and <i>y</i>, such that <i>x</i>'s return
35 * type is swap-compatible with <i>y</i>'s slot, and <i>y</i>'s return
36 * type is swap-compatible with <i>x</i>'s slot.  The subtrees rooted at
37 * <i>x</i> and <i>y</i> are swapped.
38 *
39 * <p>A "Swappable" node means a node which is capable of swapping
40 * given the existing function set.  In general to swap a node <i>foo</i>,
41 * it must have at least two children whose return types are type-compatible
42 * with each other's slots in <i>foo</i>.
43 *
44 * <p>This method is very expensive in searching nodes for
45 * "swappability".  However, if the number of types is 1 (the
46 * GP run is typeless) then the type-constraint-checking
47 * code is bypassed and the method runs a little faster.
48
49 <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
50 ...as many as the source produces
51
52 <p><b>Number of Sources</b><br>
53 1
54
55 <p><b>Parameters</b><br>
56 <table>
57 <tr><td valign=top><i>base</i>.<tt>tries</tt><br>
58 <font size=-1>int &gt;= 1</font></td>
59 <td valign=top>(number of times to try finding valid pairs of nodes)</td></tr>
60
61 <tr><td valign=top><i>base</i>.<tt>tree.0</tt><br>
62 <font size=-1>0 &lt; int &lt; (num trees in individuals), if exists</font></td>
63 <td valign=top>(tree chosen for mutation; if parameter doesn't exist, tree is picked at random)</td></tr>
64 </table>
65
66 <p><b>Default Base</b><br>
67 gp.breed.mutate-swap
68
69
70 * @author Sean Luke
71 * @version 1.0
72 */
73
74public class MutateSwapPipeline extends GPBreedingPipeline
75    {
76    public static final String P_MUTATESWAP = "mutate-swap";
77    public static final String P_NUM_TRIES = "tries";
78    public static final int NUM_SOURCES = 1;
79   
80    /** The number of times the pipeline tries to build a valid mutated
81        tree before it gives up and just passes on the original */
82    int numTries;
83
84    /** Is our tree fixed?  If not, this is -1 */
85    int tree;
86
87    public Parameter defaultBase() { return GPBreedDefaults.base().push(P_MUTATESWAP); }
88
89    public int numSources() { return NUM_SOURCES; }
90
91    public void setup(final EvolutionState state, final Parameter base)
92        {
93        super.setup(state,base);
94       
95        Parameter def = defaultBase();
96
97        numTries = state.parameters.getInt(base.push(P_NUM_TRIES),
98            def.push(P_NUM_TRIES),1);
99        if (numTries == 0)
100            state.output.fatal("MutateSwapPipeline has an invalid number of tries (it must be >= 1).",base.push(P_NUM_TRIES),def.push(P_NUM_TRIES));
101
102        tree = TREE_UNFIXED;
103        if (state.parameters.exists(base.push(P_TREE).push(""+0),
104                def.push(P_TREE).push(""+0)))
105            {
106            tree = state.parameters.getInt(base.push(P_TREE).push(""+0),
107                def.push(P_TREE).push(""+0),0);
108            if (tree==-1)
109                state.output.fatal("Tree fixed value, if defined, must be >= 0");
110            }
111        }
112
113
114    /** This very expensive method (for types)
115        might be improved in various ways I guess. */
116
117    private boolean swappable(final GPInitializer initializer,
118        final GPNode node)
119        {
120        if (node.children.length < 2)
121            return false;  // fast check
122
123        if (initializer.numAtomicTypes + initializer.numSetTypes == 1)
124            return true;  // next fast check
125
126        // we're typed, so now we have to check our type compatibility
127        for(int x=0;x<node.constraints(initializer).childtypes.length-1;x++)
128            for(int y=x+1;y<node.constraints(initializer).childtypes.length;y++)
129                if (node.children[x].constraints(initializer).returntype.compatibleWith(initializer,
130                        node.constraints(initializer).childtypes[y]) &&
131                    node.children[y].constraints(initializer).returntype.compatibleWith(initializer,
132                        node.constraints(initializer).childtypes[x]))
133                    // whew!
134                    return true;
135        return false;
136        }
137   
138   
139    private void swapSomething(final GPNode node, final EvolutionState state, final int thread)
140        {
141        if (((GPInitializer)state.initializer).numAtomicTypes + ((GPInitializer)state.initializer).numSetTypes == 1) // typeless
142            _swapSomethingTypeless(node,state,thread);
143        else _swapSomething(node,state,thread);
144        }
145
146    private void _swapSomethingTypeless(final GPNode node, final EvolutionState state, final int thread)
147        {
148        // assumes that number of child nodes >= 2
149
150        // pick a random first node
151        int x = state.random[thread].nextInt(node.children.length);
152        // pick a random second node
153        int y = state.random[thread].nextInt(node.children.length-1);
154        if (y >= x) y++; // adjust for first node
155
156        // swap the nodes
157
158        GPNode tmp = node.children[x];
159        node.children[x] = node.children[y];
160        node.children[y] = tmp;
161        node.children[x].argposition = (byte)x;
162        node.children[y].argposition = (byte)y;
163        // no need to set parent -- it's the same parent of course
164        }
165
166   
167    private void _swapSomething(final GPNode node, final EvolutionState state, final int thread)
168        {
169        int numSwappable = 0;
170        GPInitializer initializer = ((GPInitializer)state.initializer);
171        for(int x=0;x<node.constraints(initializer).childtypes.length-1;x++)
172            for(int y=x+1;y<node.constraints(initializer).childtypes.length;y++)
173                if (node.children[x].constraints(initializer).returntype.compatibleWith(initializer,
174                        node.constraints(initializer).childtypes[y]) &&
175                    node.children[y].constraints(initializer).returntype.compatibleWith(initializer,
176                        node.constraints(initializer).childtypes[x]))
177                    // whew!
178                    numSwappable++;
179
180        // pick a random item to swap -- numSwappable is assumed to be > 0
181        int swapItem = state.random[thread].nextInt(numSwappable);
182
183        numSwappable=0;
184        // find it
185
186        for(int x=0;x<node.constraints(initializer).childtypes.length-1;x++)
187            for(int y=x+1;y<node.constraints(initializer).childtypes.length;y++)
188                if (node.children[x].constraints(initializer).returntype.compatibleWith(initializer,
189                        node.constraints(initializer).childtypes[y]) &&
190                    node.children[y].constraints(initializer).returntype.compatibleWith(initializer,
191                        node.constraints(initializer).childtypes[x]))
192                    {
193                    if (numSwappable==swapItem) // found it
194                        {
195                        // swap the children
196                        GPNode tmp = node.children[x];
197                        node.children[x] = node.children[y];
198                        node.children[y] = tmp;
199                        node.children[x].argposition = (byte)x;
200                        node.children[y].argposition = (byte)y;
201                        // no need to set parent -- it's the same parent of course
202                        return;
203                        }
204                    else numSwappable++;
205                    }
206        }
207
208
209    private int numSwappableNodes(final GPInitializer initializer,
210        final GPNode root, int soFar)
211        {
212        if (swappable(initializer, root)) soFar++;
213        for(int x=0;x<root.children.length;x++)
214            soFar = numSwappableNodes(initializer, root.children[x],soFar);
215        return soFar;
216        }
217
218
219    private GPNode swappableNode;
220
221    // sticks the node in
222    private int pickSwappableNode(final GPInitializer initializer,
223        final GPNode root, int num)
224        {
225        if (swappable(initializer, root))
226            {
227            num--;
228            if (num==-1)  // found it
229                {
230                swappableNode = root;
231                return num;
232                }
233            }
234        for(int x=0;x<root.children.length;x++)
235            {
236            num = pickSwappableNode(initializer, root.children[x],num);
237            if (num==-1) break;  // someone found it
238            }
239        return num;     
240        }
241   
242
243    public int produce(final int min,
244        final int max,
245        final int start,
246        final int subpopulation,
247        final Individual[] inds,
248        final EvolutionState state,
249        final int thread)
250        {
251        // grab n individuals from our source and stick 'em right into inds.
252        // we'll modify them from there
253        int n = sources[0].produce(min,max,start,subpopulation,inds,state,thread);
254
255
256        // should we bother?
257        if (!state.random[thread].nextBoolean(likelihood))
258            return reproduce(n, start, subpopulation, inds, state, thread, false);  // DON'T produce children from source -- we already did
259
260
261
262        // now let's mutate 'em
263        for(int q=start; q < n+start; q++)
264            {
265            GPIndividual i = (GPIndividual)inds[q];
266           
267            if (tree!=TREE_UNFIXED && (tree<0 || tree >= i.trees.length))
268                // uh oh
269                state.output.fatal("MutateSwapPipeline 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");
270           
271           
272            GPIndividual j;
273            if (sources[0] instanceof BreedingPipeline)
274                // it's already a copy, so just smash the tree in
275                {
276                j=i;
277                }
278            else // need to copy it
279                {
280                j = (GPIndividual)(i.lightClone());
281               
282                // Fill in various tree information that didn't get filled in there
283                j.trees = new GPTree[i.trees.length];
284               
285                for(int x=0;x<j.trees.length;x++)
286                    {
287                    j.trees[x] = (GPTree)(i.trees[x].lightClone());
288                    j.trees[x].owner = j;
289                    j.trees[x].child = (GPNode)(i.trees[x].child.clone());
290                    j.trees[x].child.parent = j.trees[x];
291                    j.trees[x].child.argposition = 0;
292                    }
293                }
294           
295           
296            for (int x=0;x<numTries;x++)
297                {
298                int t;
299                // pick random tree
300                if (tree==TREE_UNFIXED)
301                    if (i.trees.length>1) t = state.random[thread].nextInt(i.trees.length);
302                    else t = 0;
303                else t = tree;
304               
305                // is the tree swappable?     
306                GPInitializer initializer = ((GPInitializer)state.initializer);
307                int numswap = numSwappableNodes(initializer, j.trees[t].child,0);
308                if (numswap==0) continue; // uh oh, try again
309               
310                // swap the node, or if we're unsuccessful, just leave it alone
311                pickSwappableNode(initializer, j.trees[t].child,state.random[thread].nextInt(numswap));
312               
313                // node is now in swappableNode, swap it
314                swapSomething(swappableNode,state,thread);
315
316                j.evaluated = false;
317                break;
318                }
319
320            // add the new individual, replacing its previous source
321            inds[q] = j;
322            }
323        return n;
324        }
325    }
Note: See TracBrowser for help on using the repository browser.