Clover coverage report - JGAP 3.1
Coverage timestamp: Mo Dez 11 2006 21:16:18 CET
file stats: LOC: 360   Methods: 11
NCLOC: 152   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
TwoWayMutationOperator.java 90,9% 95,8% 100% 94,5%
coverage coverage
 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 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  1 public TwoWayMutationOperator()
 61    throws InvalidConfigurationException {
 62  1 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  6 public TwoWayMutationOperator(final Configuration a_config)
 78    throws InvalidConfigurationException {
 79  6 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  17 public TwoWayMutationOperator(final Configuration a_config,
 95    final IUniversalRateCalculator
 96    a_mutationRateCalculator)
 97    throws InvalidConfigurationException {
 98  17 super(a_config);
 99  17 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  7 public TwoWayMutationOperator(final Configuration a_config,
 117    final int a_desiredMutationRate)
 118    throws InvalidConfigurationException {
 119  7 super(a_config);
 120  7 m_mutationRate = a_desiredMutationRate;
 121  7 setMutationRateCalc(null);
 122    }
 123   
 124    /**
 125    * @author Klaus Meffert
 126    * @since 2.6
 127    */
 128  12 public void operate(final Population a_population,
 129    final List a_candidateChromosomes) {
 130  12 if (a_population == null || a_candidateChromosomes == null) {
 131    // Population or candidate chromosomes list empty:
 132    // nothing to do.
 133    // -----------------------------------------------
 134  2 return;
 135    }
 136  10 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  0 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  10 boolean mutate = false;
 147  10 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  10 int size = Math.min(getConfiguration().getPopulationSize(),
 153    a_population.size());
 154  10 IGeneticOperatorConstraint constraint = getConfiguration().
 155    getJGAPFactory().getGeneticOperatorConstraint();
 156  10 for (int i = 0; i < size; i++) {
 157  18 IChromosome chrom = a_population.getChromosome(i);
 158  18 Gene[] genes = chrom.getGenes();
 159  18 IChromosome copyOfChromosome = null;
 160    // For each Chromosome in the population...
 161    // ----------------------------------------
 162  18 double d = generator.nextDouble();
 163  18 int geneIndex;
 164    /**@todo make this configurable, it is a first test,
 165    * see example DynamicMutationExample*/
 166  18 if (d >= (1 - 0.7462d)) {
 167  12 geneIndex = 3;
 168    }
 169  6 else if (d >= (1 - 0.7462d - 0.1492537d)) {
 170  0 geneIndex = 2;
 171    }
 172  6 else if (d >= (1 - 0.7462d - 0.1492537d - 0.07462686d)) {
 173  0 geneIndex = 1;
 174    }
 175    else {
 176  6 geneIndex = 0;
 177    }
 178  18 if (geneIndex >= genes.length) {
 179  10 geneIndex = genes.length - 1;
 180    }
 181   
 182  18 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  14 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  4 mutate = (generator.nextInt(m_mutationRate) == 0);
 193    }
 194  18 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  17 if (constraint != null) {
 204  2 List v = new Vector();
 205  2 v.add(chrom);
 206  2 if (!constraint.isValid(a_population, v, this)) {
 207  1 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  16 if (copyOfChromosome == null) {
 219    // ...take a copy of it...
 220    // -----------------------
 221  16 copyOfChromosome = (IChromosome) chrom.clone();
 222    // ...add it to the candidate pool...
 223    // ----------------------------------
 224  16 a_candidateChromosomes.add(copyOfChromosome);
 225    // ...then mutate all its genes...
 226    // -------------------------------
 227  16 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  16 if (genes[geneIndex] instanceof ICompositeGene) {
 234  2 ICompositeGene compositeGene = (ICompositeGene) genes[geneIndex];
 235  2 for (int k = 0; k < compositeGene.size(); k++) {
 236  2 mutateGene(compositeGene.geneAt(k), generator);
 237    }
 238    }
 239    else {
 240  14 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  16 private void mutateGene(final Gene a_gene, final RandomGenerator a_generator) {
 255  16 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  16 double percentage = -1 + a_generator.nextDouble() * 2;
 264    // 2. Mutate atomic element by calculated percentage.
 265    // --------------------------------------------------
 266  16 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  4 public IUniversalRateCalculator getMutationRateCalc() {
 277  4 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  26 public void setMutationRateCalc(final IUniversalRateCalculator
 289    a_mutationRateCalc) {
 290  26 m_mutationRateCalc = a_mutationRateCalc;
 291  26 if (m_mutationRateCalc != null) {
 292  17 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  2 public boolean equals(final Object a_other) {
 308  2 try {
 309  2 return compareTo(a_other) == 0;
 310    }
 311    catch (ClassCastException cex) {
 312  1 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  9 public int compareTo(Object a_other) {
 328  9 if (a_other == null) {
 329  1 return 1;
 330    }
 331  8 TwoWayMutationOperator op = (TwoWayMutationOperator) a_other;
 332  7 if (m_mutationRateCalc == null) {
 333  3 if (op.m_mutationRateCalc != null) {
 334  1 return -1;
 335    }
 336    }
 337    else {
 338  4 if (op.m_mutationRateCalc == null) {
 339  1 return 1;
 340    }
 341    else {
 342    }
 343    }
 344  5 if (m_mutationRate != op.m_mutationRate) {
 345  2 if (m_mutationRate > op.m_mutationRate) {
 346  1 return 1;
 347    }
 348    else {
 349  1 return -1;
 350    }
 351    }
 352    // Everything is equal. Return zero.
 353    // ---------------------------------
 354  3 return 0;
 355    }
 356   
 357  4 public int getMutationRate() {
 358  4 return m_mutationRate;
 359    }
 360    }