[6152] | 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 | } |
---|