Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OKBJavaConnector/ECJClient/src/ec/es/MuCommaLambdaBreeder.java @ 10501

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

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

File size: 14.4 KB
RevLine 
[6152]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.es;
9import ec.*;
10import ec.util.*;
11
12/*
13 * MuCommaLambdaBreeder.java
14 *
15 * Created: Thu Sep  7 17:27:47 2000
16 * By: Sean Luke
17 */
18
19/**
20 * MuCommaLambdaBreeder is a Breeder which, together with
21 * ESSelection, implements the (mu,lambda) breeding strategy and gathers
22 * the comparison data you can use to implement a 1/5-rule mutation mechanism.
23 *
24 * <p>Evolution strategies breeders require a "mu" parameter and a "lambda"
25 * parameter for each subpopulation.  "mu" refers to the number of parents
26 * from which the new population will be built.  "lambda" refers to the
27 * number of children generated by the mu parents.  Subpopulation sizes
28 * will change as necessary to accommodate this fact in later generations.
29 * The only rule for initial subpopulation sizes is that they must be
30 * greater than or equal to the mu parameter for that subpopulation.
31 *
32 * <p>You can now set your initial subpopulation
33 * size to whatever you like, totally independent of lambda and mu,
34 * as long as it is &gt;= mu.
35 *
36 * <p>MuCommaLambdaBreeder stores mu and lambda values for each subpopulation
37 * in the population, as well as comparisons.  A comparison tells you
38 * if &gt;1/5, &lt;1/5 or =1/5 of the new population was better than its
39 * parents (the so-called evolution strategies "one-fifth rule".
40 * Although the comparisons are gathered, no mutation objects are provided
41 * which actually <i>use</i> them -- you're free to use them in any mutation
42 * objects you care to devise which requires them.
43 *
44 * <p>To do evolution strategies evolution, the
45 * breeding pipelines should contain at least one ESSelection selection method.
46 * While a child is being generated by the pipeline, the ESSelection object will return a parent
47 * from the pool of mu parents.  The particular parent is chosen round-robin, so all the parents
48 * will have an equal number of children.  It's perfectly fine to have more than one ESSelection
49 * object in the tree, or to call the same one repeatedly during the course of generating a child;
50 * all such objects will consistently return the same parent.  They only increment to the next
51 * parent in the pool of mu parents after the child has been created from the pipeline.  You can
52 * also mix ESSelection operators with other operators (like Tournament Selection).  But you ought
53 * to have <b>at least one</b> ESSelection operator in the pipeline -- else it wouldn't be Evolution
54 * Strategies, would it?
55 
56 <p><b>Parameters</b><br>
57 <table>
58 <tr><td valign=top>es.lambda.<i>subpop-num</i><br>
59 <font size=-1>int >= 0</font></td><td>Specifies the 'lambda' parameter for the subpopulation.</td>
60 </tr>
61 <tr><td valign=top>es.mu.<i>subpop-num</i><br>
62 <font size=-1>int:  a multiple of "lambda"</font></td><td>Specifies the 'mu' parameter for the subpopulation.</td>
63 </tr>
64 </table>
65
66 * @author Sean Luke
67 * @version 1.0
68 */
69
70public class MuCommaLambdaBreeder extends Breeder
71    {   
72    public static final String P_MU = "mu";
73    public static final String P_LAMBDA = "lambda";
74
75    public int[] mu;
76    public int[] lambda;
77   
78    public Population parentPopulation;
79
80    public byte[] comparison;
81    public static final byte C_OVER_ONE_FIFTH_BETTER = 1;
82    public static final byte C_UNDER_ONE_FIFTH_BETTER = -1;
83    public static final byte C_EXACTLY_ONE_FIFTH_BETTER = 0;
84   
85    /** Modified by multiple threads, don't fool with this */
86    public int[] count;
87
88    public void setup(final EvolutionState state, final Parameter base)
89        {
90        // we're not using the base
91        Parameter p = new Parameter(Initializer.P_POP).push(Population.P_SIZE);
92        int size = state.parameters.getInt(p,null,1);  // if size is wrong, we'll let Population complain about it -- for us, we'll just make 0-sized arrays and drop out.
93       
94        mu = new int[size];
95        lambda = new int[size];
96        comparison = new byte[size];
97       
98        // load mu and lambda data
99        for(int x=0;x<size;x++)
100            {
101            lambda[x] = state.parameters.getInt(ESDefaults.base().push(P_LAMBDA).push(""+x),null,1);           
102            if (lambda[x]==0) state.output.error("lambda must be an integer >= 1",ESDefaults.base().push(P_LAMBDA).push(""+x));
103            mu[x] = state.parameters.getInt(ESDefaults.base().push(P_MU).push(""+x),null,1);           
104            if (mu[x]==0) state.output.error("mu must be an integer >= 1",ESDefaults.base().push(P_MU).push(""+x));
105            else if ((lambda[x] / mu[x]) * mu[x] != lambda[x]) // note integer division
106                state.output.error("mu must be a multiple of lambda", ESDefaults.base().push(P_MU).push(""+x));
107            }
108        state.output.exitIfErrors();
109        }
110
111
112
113    /** Sets all subpopulations in pop to the expected lambda size.  Does not fill new slots with individuals. */
114    public Population setToLambda(Population pop, EvolutionState state)
115        {
116        for(int x=0;x<pop.subpops.length;x++)
117            {
118            int s = lambda[x];
119           
120            // check to see if the array's not the right size
121            if (pop.subpops[x].individuals.length != s)
122                // need to increase
123                {
124                Individual[] newinds = new Individual[s];
125                System.arraycopy(pop.subpops[x].individuals,0,newinds,0,
126                    s < pop.subpops[x].individuals.length ?
127                    s : pop.subpops[x].individuals.length);
128                pop.subpops[x].individuals = newinds;
129                }
130            }
131        return pop;
132        }
133               
134
135    public Population breedPopulation(EvolutionState state)
136        {
137        // Complete 1/5 statistics for last population
138       
139        if (parentPopulation != null)
140            {
141            // Only go from 0 to lambda-1, as the remaining individuals may be parents.
142            // A child C's parent's index I is equal to C / mu[subpopulation].
143            for (int x=0;x<state.population.subpops.length;x++)
144                {
145                int numChildrenBetter = 0;
146                for (int i = 0; i < lambda[x]; i++)
147                    {
148                    int parent = i / (lambda[x] / mu[x]);  // note integer division
149                    if (state.population.subpops[x].individuals[i].fitness.betterThan(
150                            parentPopulation.subpops[x].individuals[parent].fitness))
151                        numChildrenBetter++;
152                    }
153                if (numChildrenBetter > lambda[x] / 5.0)  // note float division
154                    comparison[x] = C_OVER_ONE_FIFTH_BETTER;
155                else if (numChildrenBetter < lambda[x] / 5.0)  // note float division
156                    comparison[x] = C_UNDER_ONE_FIFTH_BETTER;
157                else comparison[x] = C_EXACTLY_ONE_FIFTH_BETTER;
158                }
159            }
160                       
161        // load the parent population
162        parentPopulation = state.population;
163       
164        // MU COMPUTATION
165       
166        // At this point we need to do load our population info
167        // and make sure it jibes with our mu info
168
169        // the first issue is: is the number of subpopulations
170        // equal to the number of mu's?
171
172        if (mu.length!=state.population.subpops.length) // uh oh
173            state.output.fatal("For some reason the number of subpops is different than was specified in the file (conflicting with Mu and Lambda storage).",null);
174
175        // next, load our population, make sure there are no subpopulations smaller than the mu's
176        for(int x=0;x<state.population.subpops.length;x++)
177            {
178            if (state.population.subpops[0].individuals.length < mu[x])
179                state.output.error("Subpopulation " + x + " must be a multiple of the equivalent mu (that is, "+ mu[x]+").");
180            }
181        state.output.exitIfErrors();
182       
183       
184
185
186        int numinds[][] =
187            new int[state.breedthreads][state.population.subpops.length];
188        int from[][] =
189            new int[state.breedthreads][state.population.subpops.length];
190           
191        // sort evaluation to get the Mu best of each subpopulation
192       
193        for(int x=0;x<state.population.subpops.length;x++)
194            {
195            final Individual[] i = state.population.subpops[x].individuals;
196
197            java.util.Arrays.sort(i,
198                new java.util.Comparator()
199                    {
200                    public int compare(Object o1, Object o2)
201                        {
202                        Individual a = (Individual) o1;
203                        Individual b = (Individual) o2;
204                        // return 1 if should appear after object b in the array.
205                        // This is the case if a has WORSE fitness.
206                        if (b.fitness.betterThan(a.fitness)) return 1;
207                        // return -1 if a should appear before object b in the array.
208                        // This is the case if b has WORSE fitness.
209                        if (a.fitness.betterThan(b.fitness)) return -1;
210                        // else return 0
211                        return 0;
212                        }
213                    });
214            }
215
216        // now the subpops are sorted so that the best individuals
217        // appear in the lowest indexes.
218
219        Population newpop = setToLambda((Population) state.population.emptyClone(),state);
220
221        // create the count array
222        count = new int[state.breedthreads];
223
224        // divvy up the lambda individuals to create
225
226        for(int y=0;y<state.breedthreads;y++)
227            for(int x=0;x<state.population.subpops.length;x++)
228                {
229                // figure numinds
230                if (y<state.breedthreads-1) // not last one
231                    numinds[y][x]=
232                        lambda[x]/state.breedthreads;
233                else // in case we're slightly off in division
234                    numinds[y][x]=
235                        lambda[x]/state.breedthreads +
236                        (lambda[x] - (lambda[x] / state.breedthreads)  // note integer division
237                        *state.breedthreads);                   
238               
239                // figure from
240                from[y][x]=
241                    (lambda[x]/
242                    state.breedthreads) * y;
243                }
244           
245        if (state.breedthreads==1)
246            {
247            breedPopChunk(newpop,state,numinds[0],from[0],0);
248            }
249        else
250            {
251            Thread[] t = new Thread[state.breedthreads];
252               
253            // start up the threads
254            for(int y=0;y<state.breedthreads;y++)
255                {
256                MuLambdaBreederThread r = new MuLambdaBreederThread();
257                r.threadnum = y;
258                r.newpop = newpop;
259                r.numinds = numinds[y];
260                r.from = from[y];
261                r.me = this;
262                r.state = state;
263                t[y] = new Thread(r);
264                t[y].start();
265                }
266               
267            // gather the threads
268            for(int y=0;y<state.breedthreads;y++) try
269                                                      {
270                                                      t[y].join();
271                                                      }
272                catch(InterruptedException e)
273                    {
274                    state.output.fatal("Whoa! The main breeding thread got interrupted!  Dying...");
275                    }
276            }
277
278        return postProcess(newpop,state.population,state);
279        }
280
281    /** A hook for Mu+Lambda, not used in Mu,Lambda */
282
283    public Population postProcess(Population newpop, Population oldpop, EvolutionState state)
284        {
285        return newpop;
286        }
287   
288   
289    int[] children;
290    int[] parents;
291   
292   
293    /** A private helper function for breedPopulation which breeds a chunk
294        of individuals in a subpopulation for a given thread.
295        Although this method is declared
296        public (for the benefit of a private helper class in this file),
297        you should not call it. */
298   
299    public void breedPopChunk(Population newpop, EvolutionState state,
300        int[] numinds, int[] from, int threadnum)
301        {
302        for(int subpop=0;subpop<newpop.subpops.length;subpop++)
303            {
304            // reset the appropriate count slot  -- this used to be outside the for-loop, a bug
305            // I believe
306            count[threadnum]=0;
307       
308            BreedingPipeline bp = (BreedingPipeline) newpop.subpops[subpop].
309                species.pipe_prototype.clone();
310           
311            // check to make sure that the breeding pipeline produces
312            // the right kind of individuals.  Don't want a mistake there! :-)
313            if (!bp.produces(state,newpop,subpop,threadnum))
314                state.output.fatal("The Breeding Pipeline of subpopulation " + subpop + " does not produce individuals of the expected species " + newpop.subpops[subpop].species.getClass().getName() + " or fitness " + newpop.subpops[subpop].species.f_prototype );
315            bp.prepareToProduce(state,subpop,threadnum);
316            if (count[threadnum] == 0)  // the ESSelection didn't set it to nonzero to inform us of his existence
317                state.output.warning("Whoa!  Breeding Pipeline for subpop " + subpop + " doesn't have an ESSelection, but is being used by MuCommaLambdaBreeder or MuPlusLambdaBreeder.  That's probably not right.");
318            // reset again
319            count[threadnum] = 0;
320       
321            // start breedin'!
322           
323            int upperbound = from[subpop]+numinds[subpop];
324            for(int x=from[subpop];x<upperbound;x++)
325                {
326                if (bp.produce(1,1,x,subpop, newpop.subpops[subpop].individuals,
327                        state,threadnum) != 1)
328                    state.output.fatal("Whoa! Breeding Pipeline for subpop " + subpop + " is not producing one individual at a time, as is required by the MuLambda strategies.");
329
330                // increment the count
331                count[threadnum]++;
332                }
333            bp.finishProducing(state,subpop,threadnum);
334            }
335        }
336    }
337
338
339/** A private helper class for implementing multithreaded breeding */
340class MuLambdaBreederThread implements Runnable
341    {
342    Population newpop;
343    public int[] numinds;
344    public int[] from;
345    public MuCommaLambdaBreeder me;
346    public EvolutionState state;
347    public int threadnum;
348    public void run()
349        {
350        me.breedPopChunk(newpop,state,numinds,from,threadnum);
351        }
352    }
353
354
Note: See TracBrowser for help on using the repository browser.