Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OKBJavaConnector/ECJClient/src/ec/select/SUSSelection.java @ 9598

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

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

File size: 6.5 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.select;
9import ec.util.*;
10import ec.*;
11
12/*
13 * SUSSelection.java
14 *
15 * Created: Thu Feb 12 16:19:52 EST 2009
16 * By: Sean Luke
17 */
18
19/**
20 * Picks individuals in a population using the Stochastic Universal Selection (SUS) process, using
21 * fitnesses as returned by their fitness() methods.  This is expensive to
22 * set up and bring down, so it's not appropriate for steady-state evolution.
23 * If you're not familiar with the relative advantages of
24 * selection methods and just want a good one,
25 * use TournamentSelection instead.   Not appropriate for
26 * multiobjective fitnesses.
27 *
28 * <p>By default this implementation of SUS shuffles the order of the individuals
29 * in the distribution before performing selection.  This isn't always present in classic
30 * implementations of the algorithm but it can't hurt anything and certainly can avoid
31 * certain pathological situations.  If you'd prefer not to preshuffle, set shuffle=false
32 * Note that we don't actually change the order of the individuals in the population -- instead
33 * we maintain our own internal array of indices and shuffle that.
34 *
35 * <p>Like truncation selection,
36 * SUS samples N individuals (with replacement) up front from the population,
37 * Then returns those individuals one by one.
38 * ECJ's implementation assumes that N is the size of the population -- that is, you're
39 * going to ultimately request a whole population out of this one selection method.
40 * This could be a false assumption: for example, if you only sometimes call this
41 * selection method, and sometimes TournamentSelection; or if you've got multiple
42 * pipelines.  In these cases, SUS is probably a bad choice anyway.
43 *
44 * <p>If you ask for <i>more</i> than a population's worth of individuals, SUS tries
45 * to handle this gracefully by reshuffling its array and starting to select over
46 * again.  But again that might suggest you are doing something wrong.
47 *
48 * <p><b><font color=red>
49 * Note: Fitnesses must be non-negative.  0 is assumed to be the worst fitness.
50 * </font></b>
51
52 <p><b>Typical Number of Individuals Produced Per <tt>produce(...)</tt> call</b><br>
53 Always 1.
54
55
56 <p><b>Parameters</b><br>
57 <table>
58 <tr><td valign=top><i>base.</i><tt>shuffle</tt><br>
59 <font size=-1> bool = <tt>true</tt> (default) or <tt>false</tt></font></td>
60 <td valign=top>(should we preshuffle the array before doing selection?)</td></tr>
61
62 </table>
63 <p><b>Default Base</b><br>
64 select.sus
65
66 *
67 * @author Sean Luke
68 * @version 1.0
69 */
70
71public class SUSSelection extends SelectionMethod
72    {
73    /** Default base */
74    public static final String P_SUS = "sus";
75    public static final String P_SHUFFLE = "shuffle";
76   
77    /** An array of pointers to individuals in the population, shuffled along with the fitnesses array. */
78    public int[] indices;
79    /** The distribution of fitnesses. */
80    public float[] fitnesses;
81   
82    /** Should we shuffle first? */
83    public boolean shuffle = true;
84    /** The floating point value to consider for the next selected individual. */
85    public float offset = 0.0f;
86    /** The index in the array of the last individual selected. */
87    public int lastIndex;
88    /** How many samples have been done?  */
89    public int steps;
90   
91    public Parameter defaultBase()
92        {
93        return SelectDefaults.base().push(P_SUS);
94        }
95
96    public void setup(final EvolutionState state, final Parameter base)
97        {
98        super.setup(state,base);
99       
100        Parameter def = defaultBase();
101        shuffle = state.parameters.getBoolean(base.push(P_SHUFFLE),def.push(P_SHUFFLE),true);
102        }
103
104    /* Largely stolen from sim.util.Bag.  Shuffles both the indices and the floats */
105    void shuffle(MersenneTwisterFast random)
106        {
107        int numObjs = fitnesses.length;
108        float[] fitnesses = this.fitnesses;
109        int[] indices = this.indices;
110       
111        float f;
112        int i;
113        int rand;
114       
115        for(int x=numObjs-1; x >= 1 ; x--)
116            {
117            rand = random.nextInt(x+1);
118            f = fitnesses[x];
119            fitnesses[x] = fitnesses[rand];
120            fitnesses[rand] = f;
121
122            i = indices[x];
123            indices[x] = indices[rand];
124            indices[rand] = i;
125            }
126        }
127
128    // don't need clone etc.
129    public void prepareToProduce(final EvolutionState s,
130        final int subpopulation,
131        final int thread)
132        {
133        lastIndex = 0;
134        steps = 0;
135       
136        // compute offset
137        offset = (float)(s.random[thread].nextDouble() / fitnesses.length);
138       
139        // load fitnesses but don't build distribution yet
140        fitnesses = new float[s.population.subpops[subpopulation].individuals.length];
141        for(int x=0;x<fitnesses.length;x++)
142            {
143            fitnesses[x] = ((Individual)(s.population.subpops[subpopulation].individuals[x])).fitness.fitness();
144            if (fitnesses[x] < 0) // uh oh
145                s.output.fatal("Discovered a negative fitness value.  SUSSelection requires that all fitness values be non-negative(offending subpopulation #" + subpopulation + ")");
146            }
147
148        // construct and optionally shuffle fitness distribution and indices
149        indices = new int[s.population.subpops[subpopulation].individuals.length];
150        for(int i=0;i<indices.length;i++) indices[i] = i;
151        if (shuffle) shuffle(s.random[thread]);
152               
153        // organize the distribution.  All zeros in fitness is fine
154        RandomChoice.organizeDistribution(fitnesses, true);
155        }
156
157    public int produce(final int subpopulation,
158        final EvolutionState state,
159        final int thread)
160        {
161        if (steps >= fitnesses.length)  // we've gone too far, clearly an error
162            {
163            state.output.warning("SUSSelection was asked for too many individuals, so we're re-shuffling.  This will give you proper results, but it might suggest an error in your code.");
164            boolean s = shuffle;
165            shuffle = true;
166            prepareToProduce(state, subpopulation, thread);  // rebuild
167            shuffle = s; // just in case
168            }
169           
170        // find the next index
171        for( /* empty */ ; lastIndex < fitnesses.length - 1; lastIndex++)
172            if ((lastIndex == 0 || offset >= fitnesses[lastIndex - 1]) && offset < fitnesses[lastIndex])
173                break;
174
175        offset += (float)(1.0 / fitnesses.length);  // update for next time
176        steps++;
177        return indices[lastIndex];
178        }
179    }
Note: See TracBrowser for help on using the repository browser.