1 | package ec.de; |
---|
2 | |
---|
3 | import ec.*; |
---|
4 | import ec.util.*; |
---|
5 | import ec.vector.*; |
---|
6 | |
---|
7 | /* |
---|
8 | * DEBreeder.java |
---|
9 | * |
---|
10 | * Created: Wed Apr 26 17:37:59 2006 |
---|
11 | * By: Liviu Panait |
---|
12 | */ |
---|
13 | |
---|
14 | /** |
---|
15 | * DEBreeder provides a straightforward Differential Evolution (DE) breeder |
---|
16 | * for the ECJ system. The code is derived from the "classic" DE algorithm, known as DE/rand/1/bin, found on page 140 of |
---|
17 | * "Differential Evolution: A Practical Approach to Global Optimization" |
---|
18 | * by Kenneth Price, Rainer Storn, and Jouni Lampinen. |
---|
19 | * |
---|
20 | * <p>DEBreeder requires that all individuals be DoubleVectorIndividuals. |
---|
21 | * |
---|
22 | * <p>In short, the algorithm is as follows. For each individual in the population, we produce a child |
---|
23 | * by selecting three (different) individuals, none the original individual, called r0, r1, and r2. |
---|
24 | * We then create an individal c, defined as c = r0 + F * (r1 - r2). Last, we cross over c with the |
---|
25 | * original individual and produce a single child, using uniform crossover with gene-independent |
---|
26 | * crossover probability "Cr". |
---|
27 | * |
---|
28 | * <p>This class should be used in conjunction with |
---|
29 | * DEEvaluator, which allows the children to enter the population only if they're superior to their |
---|
30 | * parents (the original individuals). If so, they replace their parents. |
---|
31 | * |
---|
32 | * <p><b>Parameters</b><br> |
---|
33 | * <table> |
---|
34 | * <tr><td valign=top><i>base.</i><tt>f</tt><br> |
---|
35 | * <font size=-1>0.0 <= double <= 1.0 </font></td> |
---|
36 | * <td valign=top>The "F" mutation scaling factor</td></tr> |
---|
37 | * |
---|
38 | * <tr><td valign=top><i>base.</i><tt>cr</tt><br> |
---|
39 | * <font size=-1>0.0 <= double <= 1.0 </font></td> |
---|
40 | * <td valign=top>The "Cr" probability of crossing over genes</td></tr> |
---|
41 | * </table> |
---|
42 | * |
---|
43 | * @author Liviu Panait and Sean Luke |
---|
44 | * @version 2.0 |
---|
45 | */ |
---|
46 | |
---|
47 | public class DEBreeder extends Breeder |
---|
48 | { |
---|
49 | public static final double CR_UNSPECIFIED = -1; |
---|
50 | |
---|
51 | /** Scaling factor for mutation */ |
---|
52 | public double F = 0.0; |
---|
53 | /** Probability of crossover per gene */ |
---|
54 | public double Cr = CR_UNSPECIFIED; |
---|
55 | |
---|
56 | public static final String P_F = "f"; |
---|
57 | public static final String P_Cr = "cr"; |
---|
58 | |
---|
59 | /** the previous population is stored in order to have parents compete directly with their children */ |
---|
60 | public Population previousPopulation = null; |
---|
61 | |
---|
62 | /** the best individuals in each population (required by some DE breeders). It's not required by DEBreeder's algorithm */ |
---|
63 | public int[] bestSoFarIndex = null; |
---|
64 | |
---|
65 | public void setup(final EvolutionState state, final Parameter base) |
---|
66 | { |
---|
67 | if (!state.parameters.exists(base.push(P_Cr), null)) // it wasn't specified -- hope we know what we're doing |
---|
68 | Cr = CR_UNSPECIFIED; |
---|
69 | else |
---|
70 | { |
---|
71 | Cr = state.parameters.getDouble(base.push(P_Cr),null,0.0); |
---|
72 | if ( Cr < 0.0 || Cr > 1.0 ) |
---|
73 | state.output.fatal( "Parameter not found, or its value is outside of [0.0,1.0].", base.push(P_Cr), null ); |
---|
74 | } |
---|
75 | |
---|
76 | F = state.parameters.getDouble(base.push(P_F),null,0.0); |
---|
77 | if ( F < 0.0 || F > 1.0 ) |
---|
78 | state.output.fatal( "Parameter not found, or its value is outside of [0.0,1.0].", base.push(P_F), null ); |
---|
79 | } |
---|
80 | |
---|
81 | // this function is called just before chldren are to be bred |
---|
82 | public void prepareDEBreeder(EvolutionState state) |
---|
83 | { |
---|
84 | // update the bestSoFar for each population |
---|
85 | if( bestSoFarIndex == null || state.population.subpops.length != bestSoFarIndex.length ) |
---|
86 | bestSoFarIndex = new int[state.population.subpops.length]; |
---|
87 | |
---|
88 | for( int subpop = 0 ; subpop < state.population.subpops.length ; subpop++ ) |
---|
89 | { |
---|
90 | Individual[] inds = state.population.subpops[subpop].individuals; |
---|
91 | bestSoFarIndex[subpop] = 0; |
---|
92 | for( int j = 1 ; j < inds.length ; j++ ) |
---|
93 | if( inds[j].fitness.betterThan(inds[bestSoFarIndex[subpop]].fitness) ) |
---|
94 | bestSoFarIndex[subpop] = j; |
---|
95 | } |
---|
96 | } |
---|
97 | |
---|
98 | public Population breedPopulation(EvolutionState state) |
---|
99 | { |
---|
100 | // double check that we're using DEEvaluator |
---|
101 | if (!(state.evaluator instanceof DEEvaluator)) |
---|
102 | state.output.warnOnce("DEEvaluator not used, but DEBreeder used. This is almost certainly wrong."); |
---|
103 | |
---|
104 | // prepare the breeder (some global statistics might need to be computed here) |
---|
105 | prepareDEBreeder(state); |
---|
106 | |
---|
107 | // create the new population |
---|
108 | Population newpop = (Population) state.population.emptyClone(); |
---|
109 | |
---|
110 | // breed the children |
---|
111 | for( int subpop = 0 ; subpop < state.population.subpops.length ; subpop++ ) |
---|
112 | { |
---|
113 | if (state.population.subpops[subpop].individuals.length < 4) // Magic number, sorry. createIndividual() requires at least 4 individuals in the pop |
---|
114 | state.output.fatal("Subpopulation " + subpop + " has fewer than four individuals, and so cannot be used with DEBreeder."); |
---|
115 | |
---|
116 | Individual[] inds = newpop.subpops[subpop].individuals; |
---|
117 | for( int i = 0 ; i < inds.length ; i++ ) |
---|
118 | { |
---|
119 | newpop.subpops[subpop].individuals[i] = createIndividual( state, subpop, i, 0); // unthreaded for now |
---|
120 | } |
---|
121 | } |
---|
122 | |
---|
123 | // store the current population for competition with the new children |
---|
124 | previousPopulation = state.population; |
---|
125 | return newpop; |
---|
126 | } |
---|
127 | |
---|
128 | /** Tests the Individual to see if its values are in range. */ |
---|
129 | public boolean valid(DoubleVectorIndividual ind) |
---|
130 | { |
---|
131 | FloatVectorSpecies species = (FloatVectorSpecies)(ind.species); |
---|
132 | return (!(species.mutationIsBounded && !ind.isInRange())); |
---|
133 | } |
---|
134 | |
---|
135 | public DoubleVectorIndividual createIndividual(EvolutionState state, |
---|
136 | int subpop, |
---|
137 | int index, |
---|
138 | int thread) |
---|
139 | { |
---|
140 | Individual[] inds = state.population.subpops[subpop].individuals; |
---|
141 | |
---|
142 | DoubleVectorIndividual v = (DoubleVectorIndividual)(inds[index].clone()); |
---|
143 | do |
---|
144 | { |
---|
145 | // select three indexes different from each other and from that of the current parent |
---|
146 | int r0, r1, r2; |
---|
147 | do |
---|
148 | { |
---|
149 | r0 = state.random[thread].nextInt(inds.length); |
---|
150 | } |
---|
151 | while( r0 == index ); |
---|
152 | do |
---|
153 | { |
---|
154 | r1 = state.random[thread].nextInt(inds.length); |
---|
155 | } |
---|
156 | while( r1 == r0 || r1 == index ); |
---|
157 | do |
---|
158 | { |
---|
159 | r2 = state.random[thread].nextInt(inds.length); |
---|
160 | } |
---|
161 | while( r2 == r1 || r2 == r0 || r2 == index ); |
---|
162 | |
---|
163 | DoubleVectorIndividual g0 = (DoubleVectorIndividual)(inds[r0]); |
---|
164 | DoubleVectorIndividual g1 = (DoubleVectorIndividual)(inds[r1]); |
---|
165 | DoubleVectorIndividual g2 = (DoubleVectorIndividual)(inds[r2]); |
---|
166 | |
---|
167 | for(int i = 0; i < v.genome.length; i++) |
---|
168 | v.genome[i] = g0.genome[i] + F * (g1.genome[i] - g2.genome[i]); |
---|
169 | } |
---|
170 | while(!valid(v)); |
---|
171 | |
---|
172 | return crossover(state, (DoubleVectorIndividual)(inds[index]), v, thread); |
---|
173 | } |
---|
174 | |
---|
175 | |
---|
176 | /** Crosses over child with target, storing the result in child and returning it. The default |
---|
177 | procedure copies each value from the target, with independent probability CROSSOVER, into |
---|
178 | the child. The crossover guarantees that at least one child value, chosen at random, will |
---|
179 | not be overwritten. Override this method to perform some other kind of crossover. */ |
---|
180 | |
---|
181 | public DoubleVectorIndividual crossover(EvolutionState state, DoubleVectorIndividual target, DoubleVectorIndividual child, int thread) |
---|
182 | { |
---|
183 | if (Cr == CR_UNSPECIFIED) |
---|
184 | state.output.warnOnce("Differential Evolution Parameter cr unspecified. Assuming cr = 0.5"); |
---|
185 | |
---|
186 | // first, hold one value in abeyance |
---|
187 | int index = state.random[thread].nextInt(child.genome.length); |
---|
188 | double val = child.genome[index]; |
---|
189 | |
---|
190 | // do the crossover |
---|
191 | for(int i = 0; i < child.genome.length; i++) |
---|
192 | { |
---|
193 | if (state.random[thread].nextDouble() < Cr) |
---|
194 | child.genome[i] = target.genome[i]; |
---|
195 | } |
---|
196 | |
---|
197 | // reset the one value so it's not just a duplicate copy |
---|
198 | child.genome[index] = val; |
---|
199 | |
---|
200 | return child; |
---|
201 | } |
---|
202 | |
---|
203 | } |
---|