/**
  * Marshall a Chromosome instance to an XML Element representation, including its contained Genes
  * as sub-elements. This may be useful in scenarios where representation as an entire Document is
  * undesirable, such as when the representation of this Chromosome is to be combined with other
  * elements in a single Document.
  *
  * @param a_subject the chromosome to represent as an XML element
  * @param a_xmlDocument a Document instance that will be used to create the Element instance. Note
  *     that the element will NOT be added to the document by this method
  * @return an Element object representing the given Chromosome
  * @author Neil Rotstan
  * @since 1.0
  * @deprecated use XMLDocumentBuilder instead
  */
 public static Element representChromosomeAsElement(
     final IChromosome a_subject, final Document a_xmlDocument) {
   // Start by creating an element for the chromosome and its size
   // attribute, which represents the number of genes in the chromosome.
   // ------------------------------------------------------------------
   Element chromosomeElement = a_xmlDocument.createElement(CHROMOSOME_TAG);
   chromosomeElement.setAttribute(SIZE_ATTRIBUTE, Integer.toString(a_subject.size()));
   // Next create the genes element with its nested gene elements,
   // which will contain string representations of the alleles.
   // --------------------------------------------------------------
   Element genesElement = representGenesAsElement(a_subject.getGenes(), a_xmlDocument);
   // Add the new genes element to the chromosome element and then
   // return the chromosome element.
   // -------------------------------------------------------------
   chromosomeElement.appendChild(genesElement);
   return chromosomeElement;
 }
 /**
  * Operate on the given chromosome with the given mutation rate.
  *
  * @param a_chrom chromosome to operate
  * @param a_rate mutation rate
  * @param a_generator random generator to use (must not be null)
  * @return mutated chromosome of null if no mutation has occured.
  * @author Audrius Meskauskas
  * @author Florian Hafner
  * @since 3.3.2
  */
 protected IChromosome operate(
     final IChromosome a_chrom, final int a_rate, final RandomGenerator a_generator) {
   IChromosome chromosome = null;
   // ----------------------------------------
   for (int j = m_startOffset; j < a_chrom.size(); j++) {
     // Ensure probability of 1/currentRate for applying mutation.
     // ----------------------------------------------------------
     if (a_generator.nextInt(a_rate) == 0) {
       if (chromosome == null) {
         chromosome = (IChromosome) a_chrom.clone();
         // In case monitoring is active, support it.
         // -----------------------------------------
         if (m_monitorActive) {
           chromosome.setUniqueIDTemplate(a_chrom.getUniqueID(), 1);
         }
       }
       Gene[] genes = chromosome.getGenes();
       if (m_range == 0) {
         m_range = genes.length;
       }
       Gene[] mutated = operate(a_generator, j, genes);
       // setGenes is not required for this operator, but it may
       // be needed for the derived operators.
       // ------------------------------------------------------
       try {
         chromosome.setGenes(mutated);
       } catch (InvalidConfigurationException cex) {
         throw new Error("Gene type not allowed by constraint checker", cex);
       }
     }
   }
   return chromosome;
 }
 /**
  * Convenience method that returns a new Chromosome instance with its genes values (alleles)
  * randomized. Note that, if possible, this method will acquire a Chromosome instance from the
  * active ChromosomePool (if any) and then randomize its gene values before returning it. If a
  * Chromosome cannot be acquired from the pool, then a new instance will be constructed and its
  * gene values randomized before returning it.
  *
  * @param a_configuration the configuration to use
  * @return randomly initialized Chromosome
  * @throws InvalidConfigurationException if the given Configuration instance is invalid
  * @throws IllegalArgumentException if the given Configuration instance is null
  * @author Neil Rotstan
  * @author Klaus Meffert
  * @since 1.0
  */
 public static IChromosome randomInitialChromosome(Configuration a_configuration)
     throws InvalidConfigurationException {
   // Sanity check: make sure the given configuration isn't null.
   // -----------------------------------------------------------
   if (a_configuration == null) {
     throw new IllegalArgumentException("Configuration instance must not be null");
   }
   // Lock the configuration settings so that they can't be changed
   // from now on.
   // -------------------------------------------------------------
   a_configuration.lockSettings();
   // First see if we can get a Chromosome instance from the pool.
   // If we can, we'll randomize its gene values (alleles) and then
   // return it.
   // -------------------------------------------------------------
   IChromosomePool pool = a_configuration.getChromosomePool();
   if (pool != null) {
     IChromosome randomChromosome = pool.acquireChromosome();
     if (randomChromosome != null) {
       Gene[] genes = randomChromosome.getGenes();
       RandomGenerator generator = a_configuration.getRandomGenerator();
       for (int i = 0; i < genes.length; i++) {
         genes[i].setToRandomValue(generator);
         /** @todo what about Gene's energy? */
       }
       randomChromosome.setFitnessValueDirectly(FitnessFunction.NO_FITNESS_VALUE);
       return randomChromosome;
     }
   }
   // We weren't able to get a Chromosome from the pool, so we have to
   // construct a new instance and build it from scratch.
   // ------------------------------------------------------------------
   IChromosome sampleChromosome = a_configuration.getSampleChromosome();
   sampleChromosome.setFitnessValue(FitnessFunction.NO_FITNESS_VALUE);
   Gene[] sampleGenes = sampleChromosome.getGenes();
   Gene[] newGenes = new Gene[sampleGenes.length];
   RandomGenerator generator = a_configuration.getRandomGenerator();
   for (int i = 0; i < newGenes.length; i++) {
     // We use the newGene() method on each of the genes in the
     // sample Chromosome to generate our new Gene instances for
     // the Chromosome we're returning. This guarantees that the
     // new Genes are setup with all of the correct internal state
     // for the respective gene position they're going to inhabit.
     // -----------------------------------------------------------
     newGenes[i] = sampleGenes[i].newGene();
     // Set the gene's value (allele) to a random value.
     // ------------------------------------------------
     newGenes[i].setToRandomValue(generator);
     /** @todo what about Gene's energy? */
   }
   // Finally, construct the new chromosome with the new random
   // genes values and return it.
   // ---------------------------------------------------------
   return new Chromosome(a_configuration, newGenes);
 }
 /**
  * Compares the given Chromosome to this Chromosome. This chromosome is considered to be "less
  * than" the given chromosome if it has a fewer number of genes or if any of its gene values
  * (alleles) are less than their corresponding gene values in the other chromosome.
  *
  * @param other the Chromosome against which to compare this chromosome
  * @return a negative number if this chromosome is "less than" the given chromosome, zero if they
  *     are equal to each other, and a positive number if this chromosome is "greater than" the
  *     given chromosome
  * @author Neil Rotstan
  * @author Klaus Meffert
  * @since 1.0
  */
 public int compareTo(Object other) {
   // First, if the other Chromosome is null, then this chromosome is
   // automatically the "greater" Chromosome.
   // ---------------------------------------------------------------
   if (other == null) {
     return 1;
   }
   int size = size();
   IChromosome otherChromosome = (IChromosome) other;
   Gene[] otherGenes = otherChromosome.getGenes();
   // If the other Chromosome doesn't have the same number of genes,
   // then whichever has more is the "greater" Chromosome.
   // --------------------------------------------------------------
   if (otherChromosome.size() != size) {
     return size() - otherChromosome.size();
   }
   // Next, compare the gene values (alleles) for differences. If
   // one of the genes is not equal, then we return the result of its
   // comparison.
   // ---------------------------------------------------------------
   for (int i = 0; i < size; i++) {
     int comparison = getGene(i).compareTo(otherGenes[i]);
     if (comparison != 0) {
       return comparison;
     }
   }
   // Compare current fitness value.
   // ------------------------------
   if (m_fitnessValue != otherChromosome.getFitnessValueDirectly()) {
     FitnessEvaluator eval = getConfiguration().getFitnessEvaluator();
     if (eval != null) {
       if (eval.isFitter(m_fitnessValue, otherChromosome.getFitnessValueDirectly())) {
         return 1;
       } else {
         return -1;
       }
     } else {
       // undetermined order, but unequal!
       // --------------------------------
       return -1;
     }
   }
   if (m_compareAppData) {
     // Compare application data.
     // -------------------------
     if (getApplicationData() == null) {
       if (otherChromosome.getApplicationData() != null) {
         return -1;
       }
     } else if (otherChromosome.getApplicationData() == null) {
       return 1;
     } else {
       if (getApplicationData() instanceof Comparable) {
         try {
           return ((Comparable) getApplicationData())
               .compareTo(otherChromosome.getApplicationData());
         } catch (ClassCastException cex) {
           /** @todo improve */
           return -1;
         }
       } else {
         return getApplicationData()
             .getClass()
             .getName()
             .compareTo(otherChromosome.getApplicationData().getClass().getName());
       }
     }
   }
   // Everything is equal. Return zero.
   // ---------------------------------
   return 0;
 }
 /**
  * Returns a copy of this Chromosome. The returned instance can evolve independently of this
  * instance. Note that, if possible, this method will first attempt to acquire a Chromosome
  * instance from the active ChromosomePool (if any) and set its value appropriately before
  * returning it. If that is not possible, then a new Chromosome instance will be constructed and
  * its value set appropriately before returning.
  *
  * @return copy of this Chromosome
  * @throws IllegalStateException instead of CloneNotSupportedException
  * @author Neil Rotstan
  * @author Klaus Meffert
  * @since 1.0
  */
 public synchronized Object clone() {
   // Before doing anything, make sure that a Configuration object
   // has been set on this Chromosome. If not, then throw an
   // IllegalStateException.
   // ------------------------------------------------------------
   if (getConfiguration() == null) {
     throw new IllegalStateException(
         "The active Configuration object must be set on this "
             + "Chromosome prior to invocation of the clone() method.");
   }
   IChromosome copy = null;
   // Now, first see if we can pull a Chromosome from the pool and just
   // set its gene values (alleles) appropriately.
   // ------------------------------------------------------------
   IChromosomePool pool = getConfiguration().getChromosomePool();
   if (pool != null) {
     copy = pool.acquireChromosome();
     if (copy != null) {
       Gene[] genes = copy.getGenes();
       for (int i = 0; i < size(); i++) {
         genes[i].setAllele(getGene(i).getAllele());
       }
     }
   }
   try {
     if (copy == null) {
       // We couldn't fetch a Chromosome from the pool, so we need to create
       // a new one. First we make a copy of each of the Genes. We explicity
       // use the Gene at each respective gene location (locus) to create the
       // new Gene that is to occupy that same locus in the new Chromosome.
       // -------------------------------------------------------------------
       int size = size();
       if (size > 0) {
         Gene[] copyOfGenes = new Gene[size];
         for (int i = 0; i < copyOfGenes.length; i++) {
           copyOfGenes[i] = getGene(i).newGene();
           Object allele = getGene(i).getAllele();
           if (allele != null) {
             IJGAPFactory factory = getConfiguration().getJGAPFactory();
             if (factory != null) {
               ICloneHandler cloner = factory.getCloneHandlerFor(allele, allele.getClass());
               if (cloner != null) {
                 try {
                   allele = cloner.perform(allele, null, this);
                 } catch (Exception ex) {
                   throw new RuntimeException(ex);
                 }
               }
             }
           }
           copyOfGenes[i].setAllele(allele);
         }
         // Now construct a new Chromosome with the copies of the genes and
         // return it. Also clone the IApplicationData object later on.
         // ---------------------------------------------------------------
         if (getClass() == Chromosome.class) {
           copy = new Chromosome(getConfiguration(), copyOfGenes);
         } else {
           copy = (IChromosome) getConfiguration().getSampleChromosome().clone();
           copy.setGenes(copyOfGenes);
         }
       } else {
         if (getClass() == Chromosome.class) {
           copy = new Chromosome(getConfiguration());
         } else {
           copy = (IChromosome) getConfiguration().getSampleChromosome().clone();
         }
       }
     }
     copy.setFitnessValue(m_fitnessValue);
     // Clone constraint checker.
     // -------------------------
     copy.setConstraintChecker(getConstraintChecker());
   } catch (InvalidConfigurationException iex) {
     throw new IllegalStateException(iex.getMessage());
   }
   // Also clone the IApplicationData object.
   // ---------------------------------------
   try {
     copy.setApplicationData(cloneObject(getApplicationData()));
   } catch (Exception ex) {
     throw new IllegalStateException(ex.getMessage());
   }
   // Clone multi-objective object if necessary and possible.
   // -------------------------------------------------------
   if (m_multiObjective != null) {
     if (getClass() == Chromosome.class) {
       try {
         ((Chromosome) copy).setMultiObjectives((List) cloneObject(m_multiObjective));
       } catch (Exception ex) {
         throw new IllegalStateException(ex.getMessage());
       }
     }
   }
   return copy;
 }