KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jgap > impl > TwoWayMutationOperator


1 /*
2  * This file is part of JGAP.
3  *
4  * JGAP offers a dual license model containing the LGPL as well as the MPL.
5  *
6  * For licencing information please see the file license.txt included with JGAP
7  * or have a look at the top of class org.jgap.Chromosome which representatively
8  * includes the JGAP license policy applicable for any file delivered with JGAP.
9  */

10 package org.jgap.impl;
11
12 import java.util.*;
13 import org.jgap.*;
14
15 /**
16  * Considers two levels of mutation. At first, this mutation operator assumes
17  * all genes within a chromosome to having a different impact on the result
18  * when mutated. For that, a gene with fewer impact is selected for mutation more
19  * likely than one with bigger impact. After a gene has been selected for
20  * mutation, it is indeed mutated in a traditional way.
21  * <p>
22  * See class examples.dynamicMutation.DynamicMutationExample for usage,
23  * currently this class only works with that example!
24  *
25  * @author Klaus Meffert
26  * @since 2.6
27  */

28 public class TwoWayMutationOperator
29     extends BaseGeneticOperator {
30   /** String containing the CVS revision. Read out via reflection!*/
31   private final static String JavaDoc CVS_REVISION = "$Revision: 1.6 $";
32
33   /**
34    * The current mutation rate used by this MutationOperator, expressed as
35    * the denominator in the 1 / X ratio. For example, X = 1000 would
36    * mean that, on average, 1 / 1000 genes would be mutated. A value of zero
37    * disables mutation entirely.
38    */

39   private int m_mutationRate;
40
41   /**
42    * Calculator for dynamically determining the mutation rate. If set to
43    * null the value of m_mutationRate will be used. Replaces the previously used
44    * boolean m_dynamicMutationRate.
45    */

46   private IUniversalRateCalculator m_mutationRateCalc;
47
48   /**
49    * Constructs a new instance of this MutationOperator without a specified
50    * mutation rate, which results in dynamic mutation being turned on. This
51    * means that the mutation rate will be automatically determined by this
52    * operator based upon the number of genes present in the chromosomes.<p>
53    * Attention: The configuration used is the one set with the static method
54    * Genotype.setConfiguration.
55    * @throws InvalidConfigurationException
56    *
57    * @author Klaus Meffert
58    * @since 2.6
59    */

60   public TwoWayMutationOperator()
61       throws InvalidConfigurationException {
62     this(Genotype.getStaticConfiguration(),
63          new DefaultMutationRateCalculator(Genotype.getStaticConfiguration()));
64   }
65
66   /**
67    * Constructs a new instance of this MutationOperator without a specified
68    * mutation rate, which results in dynamic mutation being turned on. This
69    * means that the mutation rate will be automatically determined by this
70    * operator based upon the number of genes present in the chromosomes.<p>
71    * @param a_config the configuration to use
72    * @throws InvalidConfigurationException
73    *
74    * @author Klaus Meffert
75    * @since 3.1
76    */

77   public TwoWayMutationOperator(final Configuration a_config)
78       throws InvalidConfigurationException {
79     this(a_config, new DefaultMutationRateCalculator(a_config));
80   }
81
82   /**
83    * Constructs a new instance of this MutationOperator with a specified
84    * mutation rate calculator, which results in dynamic mutation being turned
85    * on.
86    * @param a_config the configuration to use
87    * @param a_mutationRateCalculator calculator for dynamic mutation rate
88    * computation
89    * @throws InvalidConfigurationException
90    *
91    * @author Klaus Meffert
92    * @since 2.6
93    */

94   public TwoWayMutationOperator(final Configuration a_config,
95                                 final IUniversalRateCalculator
96                                 a_mutationRateCalculator)
97       throws InvalidConfigurationException {
98     super(a_config);
99     setMutationRateCalc(a_mutationRateCalculator);
100   }
101
102   /**
103    * Constructs a new instance of this MutationOperator with the given
104    * mutation rate.
105    *
106    * @param a_config the configuration to use
107    * @param a_desiredMutationRate desired rate of mutation, expressed as
108    * the denominator of the 1 / X fraction. For example, 1000 would result
109    * in 1/1000 genes being mutated on average. A mutation rate of zero disables
110    * mutation entirely
111    * @throws InvalidConfigurationException
112    *
113    * @author Klaus Meffert
114    * @since 2.6
115    */

116   public TwoWayMutationOperator(final Configuration a_config,
117                                 final int a_desiredMutationRate)
118       throws InvalidConfigurationException {
119     super(a_config);
120     m_mutationRate = a_desiredMutationRate;
121     setMutationRateCalc(null);
122   }
123
124   /**
125    * @author Klaus Meffert
126    * @since 2.6
127    */

128   public void operate(final Population a_population,
129                       final List a_candidateChromosomes) {
130     if (a_population == null || a_candidateChromosomes == null) {
131       // Population or candidate chromosomes list empty:
132
// nothing to do.
133
// -----------------------------------------------
134
return;
135     }
136     if (m_mutationRate == 0 && m_mutationRateCalc == null) {
137       // If the mutation rate is set to zero and dynamic mutation rate is
138
// disabled, then we don't perform any mutation.
139
// ----------------------------------------------------------------
140
return;
141     }
142     // Determine the mutation rate. If dynamic rate is enabled, then
143
// calculate it using the IUniversalRateCalculator instance.
144
// Otherwise, go with the mutation rate set upon construction.
145
// -------------------------------------------------------------
146
boolean mutate = false;
147     RandomGenerator generator = getConfiguration().getRandomGenerator();
148     // It would be inefficient to create copies of each Chromosome just
149
// to decide whether to mutate them. Instead, we only make a copy
150
// once we've positively decided to perform a mutation.
151
// ----------------------------------------------------------------
152
int size = Math.min(getConfiguration().getPopulationSize(),
153                         a_population.size());
154     IGeneticOperatorConstraint constraint = getConfiguration().
155         getJGAPFactory().getGeneticOperatorConstraint();
156     for (int i = 0; i < size; i++) {
157       IChromosome chrom = a_population.getChromosome(i);
158       Gene[] genes = chrom.getGenes();
159       IChromosome copyOfChromosome = null;
160       // For each Chromosome in the population...
161
// ----------------------------------------
162
double d = generator.nextDouble();
163       int geneIndex;
164       /**@todo make this configurable, it is a first test,
165        * see example DynamicMutationExample*/

166       if (d >= (1 - 0.7462d)) {
167         geneIndex = 3;
168       }
169       else if (d >= (1 - 0.7462d - 0.1492537d)) {
170         geneIndex = 2;
171       }
172       else if (d >= (1 - 0.7462d - 0.1492537d - 0.07462686d)) {
173         geneIndex = 1;
174       }
175       else {
176         geneIndex = 0;
177       }
178       if (geneIndex >= genes.length) {
179         geneIndex = genes.length - 1;
180       }
181
182       if (m_mutationRateCalc != null) {
183         // If it's a dynamic mutation rate then let the calculator decide
184
// whether the current gene should be mutated.
185
// --------------------------------------------------------------
186
mutate = m_mutationRateCalc.toBePermutated(chrom, geneIndex);
187       }
188       else {
189         // Non-dynamic, so just mutate based on the the current rate.
190
// In fact we use a rate of 1/m_mutationRate.
191
// ----------------------------------------------------------
192
mutate = (generator.nextInt(m_mutationRate) == 0);
193       }
194       if (mutate) {
195 // if (m_mutationManager != null) {
196
// if (!m_mutationManager.doMutate(chrom,j)) {
197
// continue;
198
// }
199
// }
200
// Verify that crossover allowed.
201
// ------------------------------
202
/**@todo move to base class, refactor*/
203         if (constraint != null) {
204           List v = new Vector();
205           v.add(chrom);
206           if (!constraint.isValid(a_population, v, this)) {
207             continue;
208           }
209         }
210         // Now that we want to actually modify the Chromosome,
211
// let's make a copy of it (if we haven't already) and
212
// add it to the candidate chromosomes so that it will
213
// be considered for natural selection during the next
214
// phase of evolution. Then we'll set the gene's value
215
// to a random value as the implementation of our
216
// "mutation" of the gene.
217
// ---------------------------------------------------
218
if (copyOfChromosome == null) {
219           // ...take a copy of it...
220
// -----------------------
221
copyOfChromosome = (IChromosome) chrom.clone();
222           // ...add it to the candidate pool...
223
// ----------------------------------
224
a_candidateChromosomes.add(copyOfChromosome);
225           // ...then mutate all its genes...
226
// -------------------------------
227
genes = copyOfChromosome.getGenes();
228         }
229         // Process all atomic elements in the gene. For a StringGene this
230
// would be the length of the string, for an IntegerGene, it is
231
// always one element.
232
// --------------------------------------------------------------
233
if (genes[geneIndex] instanceof ICompositeGene) {
234           ICompositeGene compositeGene = (ICompositeGene) genes[geneIndex];
235           for (int k = 0; k < compositeGene.size(); k++) {
236             mutateGene(compositeGene.geneAt(k), generator);
237           }
238         }
239         else {
240           mutateGene(genes[geneIndex], generator);
241         }
242       }
243     }
244   }
245
246   /**
247    * Helper: mutate all atomic elements of a gene
248    * @param a_gene the gene to be mutated
249    * @param a_generator the generator delivering amount of mutation
250    *
251    * @author Klaus Meffert
252    * @since 2.6
253    */

254   private void mutateGene(final Gene a_gene, final RandomGenerator a_generator) {
255     for (int k = 0; k < a_gene.size(); k++) {
256       // 1. Select a gene (assuming genes are ordered regarding their impact
257
// on the result, if mutated)
258
// -------------------------------------------------------------------
259

260       // Retrieve value between 0 and 1 (not included) from generator.
261
// Then map this value to range -1 and 1 (-1 included, 1 not).
262
// -------------------------------------------------------------
263
double percentage = -1 + a_generator.nextDouble() * 2;
264       // 2. Mutate atomic element by calculated percentage.
265
// --------------------------------------------------
266
a_gene.applyMutation(k, percentage);
267     }
268   }
269
270   /**
271    * @return the MutationRateCalculator used
272    *
273    * @author Klaus Meffert
274    * @since 1.1
275    */

276   public IUniversalRateCalculator getMutationRateCalc() {
277     return m_mutationRateCalc;
278   }
279
280   /**
281    * Sets the MutationRateCalculator to be used for determining the strength of
282    * mutation.
283    * @param a_mutationRateCalc MutationRateCalculator
284    *
285    * @author Klaus Meffert
286    * @since 1.1
287    */

288   public void setMutationRateCalc(final IUniversalRateCalculator
289                                   a_mutationRateCalc) {
290     m_mutationRateCalc = a_mutationRateCalc;
291     if (m_mutationRateCalc != null) {
292       m_mutationRate = 0;
293     }
294   }
295
296   /**
297    * Compares this GeneticOperator against the specified object. The result is
298    * true if and the argument is an instance of this class and is equal wrt the
299    * data.
300    *
301    * @param a_other the object to compare against
302    * @return true: if the objects are the same, false otherwise
303    *
304    * @author Klaus Meffert
305    * @since 2.6
306    */

307   public boolean equals(final Object JavaDoc a_other) {
308     try {
309       return compareTo(a_other) == 0;
310     }
311     catch (ClassCastException JavaDoc cex) {
312       return false;
313     }
314   }
315
316   /**
317    * Compares the given GeneticOperator to this GeneticOperator.
318    *
319    * @param a_other the instance against which to compare this instance
320    * @return a negative number if this instance is "less than" the given
321    * instance, zero if they are equal to each other, and a positive number if
322    * this is "greater than" the given instance
323    *
324    * @author Klaus Meffert
325    * @since 2.6
326    */

327   public int compareTo(Object JavaDoc a_other) {
328     if (a_other == null) {
329       return 1;
330     }
331     TwoWayMutationOperator op = (TwoWayMutationOperator) a_other;
332     if (m_mutationRateCalc == null) {
333       if (op.m_mutationRateCalc != null) {
334         return -1;
335       }
336     }
337     else {
338       if (op.m_mutationRateCalc == null) {
339         return 1;
340       }
341       else {
342       }
343     }
344     if (m_mutationRate != op.m_mutationRate) {
345       if (m_mutationRate > op.m_mutationRate) {
346         return 1;
347       }
348       else {
349         return -1;
350       }
351     }
352     // Everything is equal. Return zero.
353
// ---------------------------------
354
return 0;
355   }
356
357   public int getMutationRate() {
358     return m_mutationRate;
359   }
360 }
361
Popular Tags