Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OKBJavaConnector/ECJClient/src/ec/gp/koza/MutationPipeline.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: 11.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.koza;
9import ec.*;
10import ec.util.*;
11import ec.gp.*;
12
13/*
14 * MutationPipeline.java
15 *
16 * Created: Tue Oct 12 18:50:56 1999
17 * By: Sean Luke
18 */
19
20/**
21 * MutationPipeline is a GPBreedingPipeline which
22 * implements a strongly-typed version of the
23 * "Point Mutation" operator as described in Koza I.
24 * Actually, that's not quite true.  Koza doesn't have any tree depth restrictions
25 * on his mutation operator.  This one does -- if the tree gets deeper than
26 * the maximum tree depth, then the new subtree is rejected and another one is
27 * tried.  Similar to how the Crosssover operator is implemented.
28 *
29 * <p>Mutated trees are restricted to being <tt>maxdepth</tt> depth at most.
30 * If in <tt>tries</tt> attemptes, the pipeline cannot come up with a mutated
31 * tree within the depth limit, then it simply copies the original individual
32 * wholesale with no mutation.
33 *
34 * <p>One additional feature: if <tt>equal</tt> is true, then MutationPipeline
35 * will attempt to replace the subtree with a tree of approximately equal size.
36 * How this is done exactly, and how close it is, is entirely up to the pipeline's
37 * tree builder -- for example, Grow/Full/HalfBuilder don't support this at all, while
38 * RandomBranch will replace it with a tree of the same size or "slightly smaller"
39 * as described in the algorithm.
40
41 <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
42 ...as many as the child produces
43
44 <p><b>Number of Sources</b><br>
45 1
46
47 <p><b>Parameters</b><br>
48 <table>
49 <tr><td valign=top><i>base</i>.<tt>tries</tt><br>
50 <font size=-1>int &gt;= 1</font></td>
51 <td valign=top>(number of times to try finding valid pairs of nodes)</td></tr>
52
53 <tr><td valign=top><i>base</i>.<tt>maxdepth</tt><br>
54 <font size=-1>int &gt;= 1</font></td>
55 <td valign=top>(maximum valid depth of a crossed-over subtree)</td></tr>
56
57 <tr><td valign=top><i>base</i>.<tt>ns</tt><br>
58 <font size=-1>classname, inherits and != GPNodeSelector</font></td>
59 <td valign=top>(GPNodeSelector for tree)</td></tr>
60
61 <tr><td valign=top><i>base</i>.<tt>build</tt>.0<br>
62 <font size=-1>classname, inherits and != GPNodeBuilder</font></td>
63 <td valign=top>(GPNodeBuilder for new subtree)</td></tr>
64
65 <tr><td valign=top><tt>equal</tt><br>
66 <font size=-1>bool = <tt>true</tt> or <tt>false</tt> (default)</td>
67 <td valign=top>(do we attempt to replace the subtree with a new one of roughly the same size?)</td></tr>
68
69 <tr><td valign=top><i>base</i>.<tt>tree.0</tt><br>
70 <font size=-1>0 &lt; int &lt; (num trees in individuals), if exists</font></td>
71 <td valign=top>(tree chosen for mutation; if parameter doesn't exist, tree is picked at random)</td></tr>
72
73 </table>
74
75 <p><b>Default Base</b><br>
76 gp.koza.mutate
77
78 <p><b>Parameter bases</b><br>
79 <table>
80
81 <tr><td valign=top><i>base</i>.<tt>ns</tt><br>
82 <td>nodeselect</td></tr>
83
84 <tr><td valign=top><i>base</i>.<tt>build</tt><br>
85 <td>builder</td></tr>
86
87 </table>
88
89
90
91 * @author Sean Luke
92 * @version 1.0
93 */
94
95public class MutationPipeline extends GPBreedingPipeline
96    {
97    public static final String P_NUM_TRIES = "tries";
98    public static final String P_MAXDEPTH = "maxdepth";
99    public static final String P_MUTATION = "mutate";
100    public static final String P_BUILDER = "build";
101    public static final String P_EQUALSIZE = "equal";
102    public static final int INDS_PRODUCED = 1;
103    public static final int NUM_SOURCES = 1;
104
105    /** How the pipeline chooses a subtree to mutate */
106    public GPNodeSelector nodeselect;
107
108    /** How the pipeline builds a new subtree */
109    public GPNodeBuilder builder;
110
111    /** The number of times the pipeline tries to build a valid mutated
112        tree before it gives up and just passes on the original */
113    int numTries;
114   
115    /** The maximum depth of a mutated tree */
116    int maxDepth;
117
118    /** Do we try to replace the subtree with another of the same size? */
119    boolean equalSize;
120
121    /** Is our tree fixed?  If not, this is -1 */
122    int tree;
123
124    public Parameter defaultBase() { return GPKozaDefaults.base().push(P_MUTATION); }
125
126    public int numSources() { return NUM_SOURCES; }
127
128    public Object clone()
129        {
130        MutationPipeline c = (MutationPipeline)(super.clone());
131
132        // deep-cloned stuff
133        c.nodeselect = (GPNodeSelector)(nodeselect.clone());
134
135        return c;
136        }
137
138    public void setup(final EvolutionState state, final Parameter base)
139        {
140        super.setup(state,base);
141       
142        Parameter def = defaultBase();
143        Parameter p = base.push(P_NODESELECTOR).push(""+0);
144        Parameter d = def.push(P_NODESELECTOR).push(""+0);
145
146        nodeselect = (GPNodeSelector)
147            (state.parameters.getInstanceForParameter(
148                p,d, GPNodeSelector.class));
149        nodeselect.setup(state,p);
150
151        p = base.push(P_BUILDER).push(""+0);
152        d = def.push(P_BUILDER).push(""+0);
153
154        builder = (GPNodeBuilder)
155            (state.parameters.getInstanceForParameter(
156                p,d, GPNodeBuilder.class));
157        builder.setup(state,p);
158
159        numTries = state.parameters.getInt(
160            base.push(P_NUM_TRIES),def.push(P_NUM_TRIES),1);
161        if (numTries ==0)
162            state.output.fatal("Mutation Pipeline has an invalid number of tries (it must be >= 1).",base.push(P_NUM_TRIES),def.push(P_NUM_TRIES));
163
164        maxDepth = state.parameters.getInt(
165            base.push(P_MAXDEPTH),def.push(P_MAXDEPTH),1);
166        if (maxDepth==0)
167            state.output.fatal("The Mutation Pipeline " + base + "has an invalid maximum depth (it must be >= 1).",base.push(P_MAXDEPTH),def.push(P_MAXDEPTH));
168
169        equalSize = state.parameters.getBoolean(
170            base.push(P_EQUALSIZE),def.push(P_EQUALSIZE),false);
171
172        tree = TREE_UNFIXED;
173        if (state.parameters.exists(base.push(P_TREE).push(""+0),
174                def.push(P_TREE).push(""+0)))
175            {
176            tree = state.parameters.getInt(base.push(P_TREE).push(""+0),
177                def.push(P_TREE).push(""+0),0);
178            if (tree==-1)
179                state.output.fatal("Tree fixed value, if defined, must be >= 0");
180            }
181        }
182
183
184    /** Returns true if inner1 can feasibly be swapped into inner2's position */
185
186    public boolean verifyPoints(GPNode inner1, GPNode inner2)
187        {
188        // We know they're swap-compatible since we generated inner1
189        // to be exactly that.  So don't bother.
190
191        // next check to see if inner1 can fit in inner2's spot
192        if (inner1.depth()+inner2.atDepth() > maxDepth) return false;
193
194        // checks done!
195        return true;
196        }
197
198
199
200
201    public int produce(final int min,
202        final int max,
203        final int start,
204        final int subpopulation,
205        final Individual[] inds,
206        final EvolutionState state,
207        final int thread)
208        {
209        // grab individuals from our source and stick 'em right into inds.
210        // we'll modify them from there
211        int n = sources[0].produce(min,max,start,subpopulation,inds,state,thread);
212
213        // should we bother?
214        if (!state.random[thread].nextBoolean(likelihood))
215            return reproduce(n, start, subpopulation, inds, state, thread, false);  // DON'T produce children from source -- we already did
216
217
218        GPInitializer initializer = ((GPInitializer)state.initializer);
219
220        // now let's mutate 'em
221        for(int q=start; q < n+start; q++)
222            {
223            GPIndividual i = (GPIndividual)inds[q];
224
225            if (tree!=TREE_UNFIXED && (tree<0 || tree >= i.trees.length))
226                // uh oh
227                state.output.fatal("GP Mutation Pipeline 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");
228               
229
230            int t;
231            // pick random tree
232            if (tree==TREE_UNFIXED)
233                if (i.trees.length>1) t = state.random[thread].nextInt(i.trees.length);
234                else t = 0;
235            else t = tree;
236
237            // validity result...
238            boolean res = false;
239           
240            // prepare the nodeselector
241            nodeselect.reset();
242           
243            // pick a node
244           
245            GPNode p1=null;  // the node we pick
246            GPNode p2=null;
247           
248            for(int x=0;x<numTries;x++)
249                {
250                // pick a node in individual 1
251                p1 = nodeselect.pickNode(state,subpopulation,thread,i,i.trees[t]);
252               
253                // generate a tree swap-compatible with p1's position
254               
255               
256                int size = GPNodeBuilder.NOSIZEGIVEN;
257                if (equalSize) size = p1.numNodes(GPNode.NODESEARCH_ALL);
258
259                p2 = builder.newRootedTree(state,
260                    p1.parentType(initializer),
261                    thread,
262                    p1.parent,
263                    i.trees[t].constraints(initializer).functionset,
264                    p1.argposition,
265                    size);
266               
267                // check for depth and swap-compatibility limits
268                res = verifyPoints(p2,p1);  // p2 can fit in p1's spot  -- the order is important!
269               
270                // did we get something that had both nodes verified?
271                if (res) break;
272                }
273           
274            GPIndividual j;
275
276            if (sources[0] instanceof BreedingPipeline)
277                // it's already a copy, so just smash the tree in
278                {
279                j=i;
280                if (res)  // we're in business
281                    {
282                    p2.parent = p1.parent;
283                    p2.argposition = p1.argposition;
284                    if (p2.parent instanceof GPNode)
285                        ((GPNode)(p2.parent)).children[p2.argposition] = p2;
286                    else ((GPTree)(p2.parent)).child = p2;
287                    j.evaluated = false;  // we've modified it
288                    }
289                }
290            else // need to clone the individual
291                {
292                j = (GPIndividual)(i.lightClone());
293               
294                // Fill in various tree information that didn't get filled in there
295                j.trees = new GPTree[i.trees.length];
296               
297                // at this point, p1 or p2, or both, may be null.
298                // If not, swap one in.  Else just copy the parent.
299                for(int x=0;x<j.trees.length;x++)
300                    {
301                    if (x==t && res)  // we've got a tree with a kicking cross position!
302                        {
303                        j.trees[x] = (GPTree)(i.trees[x].lightClone());
304                        j.trees[x].owner = j;
305                        j.trees[x].child = i.trees[x].child.cloneReplacingNoSubclone(p2,p1);
306                        j.trees[x].child.parent = j.trees[x];
307                        j.trees[x].child.argposition = 0;
308                        j.evaluated = false;
309                        } // it's changed
310                    else
311                        {
312                        j.trees[x] = (GPTree)(i.trees[x].lightClone());
313                        j.trees[x].owner = j;
314                        j.trees[x].child = (GPNode)(i.trees[x].child.clone());
315                        j.trees[x].child.parent = j.trees[x];
316                        j.trees[x].child.argposition = 0;                   
317                        }
318                    }
319                }
320           
321            // add the new individual, replacing its previous source
322            inds[q] = j;
323            }
324        return n;
325        }
326    }
Note: See TracBrowser for help on using the repository browser.