Clover coverage report - JGAP 3.1
Coverage timestamp: Mo Dez 11 2006 21:16:18 CET
file stats: LOC: 1.041   Methods: 39
NCLOC: 408   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
Chromosome.java 94,1% 93,7% 94,9% 93,9%
coverage coverage
 1    /**
 2    * JGAP offers a dual license model(see below for specific license information):
 3    * + The LGPL may be used anytime.
 4    * + The MPL may be used if at least $20 have been donated to the JGAP project
 5    * thru PayPal (see http://www.sourceforge.net/projects/jgap or, directly,
 6    * http://sourceforge.net/donate/index.php?group_id=11618).
 7    * Details about usage of JGAP under the MPL can be found at the homepage
 8    * http://jgap.sourceforge.net/.
 9    *
 10    * Specific license information (MPL and LGPL)
 11    * -------------------------------------------
 12    * The contents of this file are subject to the Mozilla Public License Version
 13    * 1.1 (the "License"); you may not use this file except in compliance with the
 14    * License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
 15    *
 16    * Software distributed under the License is distributed on an "AS IS" basis,
 17    * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 18    * the specific language governing rights and limitations under the License.
 19    *
 20    * The Original Code is 'JGAP - Java Genetic Algorithms Package'.
 21    * The Initial Developer of the Original Code is Neil Rotstan. Portions created
 22    * by the Initial Developer are Copyright (C) 2002- 2003 by Neil Rotstan.
 23    * All Rights Reserved.
 24    * Co-developer of the code is Klaus Meffert. Portions created by the co-
 25    * developer are Copyright (C) 2003-2006 by Klaus Meffert. All Rights Reserved.
 26    * Contributor(s): all the names of the contributors are added in the source
 27    * code where applicable.
 28    *
 29    * Alternatively, the contents of this file may be used under the terms of the
 30    * LGPL license (the "GNU LESSER PUBLIC LICENSE"), in which case the
 31    * provisions of LGPL are applicable instead of those above. If you wish to
 32    * allow use of your version of this file only under the terms of the LGPL
 33    * License and not to allow others to use your version of this file under
 34    * the MPL, indicate your decision by deleting the provisions above and
 35    * replace them with the notice and other provisions required by the LGPL.
 36    * If you do not delete the provisions above, a recipient may use your version
 37    * of this file under either the MPL or the LGPL.
 38    *
 39    * This library is free software; you can redistribute it and/or modify it
 40    * under the terms of the MPL as stated above or under the terms of the LGPL.
 41    * This library is distributed in the hope that it will be useful, but WITHOUT
 42    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 43    * FOR A PARTICULAR PURPOSE. See the GNU Lesser Public License for more
 44    * details.
 45    */
 46    package org.jgap;
 47   
 48    import java.util.*;
 49   
 50    /**
 51    * Chromosomes represent potential solutions and consist of a fixed-length
 52    * collection of genes. Each gene represents a discrete part of the solution.
 53    * Each gene in the Chromosome may be backed by a different concrete
 54    * implementation of the Gene interface, but all genes in a respective
 55    * position (locus) must share the same concrete implementation across
 56    * Chromosomes within a single population (genotype). In other words, gene 1
 57    * in a chromosome must share the same concrete implementation as gene 1 in all
 58    * other chromosomes in the population.
 59    *
 60    * @author Neil Rotstan
 61    * @author Klaus Meffert
 62    * @since 1.0
 63    */
 64    public class Chromosome
 65    extends BaseChromosome {
 66    /** String containing the CVS revision. Read out via reflection!*/
 67    private final static String CVS_REVISION = "$Revision: 1.86 $";
 68   
 69    /**
 70    * Application-specific data that is attached to this Chromosome.
 71    * This data may assist the application in evaluating this Chromosome
 72    * in the fitness function. JGAP does not operate on the data, aside
 73    * from allowing it to be set and retrieved, and considering it with
 74    * comparations (if user opted in to do so).
 75    */
 76    private Object m_applicationData;
 77   
 78    /**
 79    * Holding multiobjective values
 80    * @since 2.6
 81    * @todo move to new subclass of Chromosome (and introduce new interface
 82    * IMultiObjective with that)
 83    */
 84    private List m_multiObjective;
 85   
 86    /**
 87    * The array of Genes contained in this Chromosome.
 88    */
 89    private Gene[] m_genes;
 90   
 91    /**
 92    * Keeps track of whether or not this Chromosome has been selected by
 93    * the natural selector to move on to the next generation.
 94    */
 95    private boolean m_isSelectedForNextGeneration;
 96   
 97    /**
 98    * Stores the fitness value of this Chromosome as determined by the
 99    * active fitness function. A value of -1 indicates that this field
 100    * has not yet been set with this Chromosome's fitness values (valid
 101    * fitness values are always positive).
 102    *
 103    * @since 2.0 (until 1.1: type int)
 104    */
 105    protected double m_fitnessValue = FitnessFunction.NO_FITNESS_VALUE;
 106   
 107    /**
 108    * Method compareTo(): Should we also consider the application data when
 109    * comparing? Default is "false" as "true" means a Chromosome's losing its
 110    * identity when application data is set differently!
 111    *
 112    * @since 2.2
 113    */
 114    private boolean m_compareAppData;
 115   
 116    /**
 117    * Optional helper class for checking if a given allele value to be set
 118    * for a given gene is valid. If not, the allele value may not be set for the
 119    * gene or the gene type (e.g. IntegerGene) is not allowed in general!
 120    *
 121    * @since 2.5
 122    */
 123    private IGeneConstraintChecker m_geneAlleleChecker;
 124   
 125    /**
 126    * Default constructor, provided for dynamic instantiation.<p>
 127    * Attention: The configuration used is the one set with the static method
 128    * Genotype.setConfiguration.
 129    * @throws InvalidConfigurationException
 130    *
 131    * @author Klaus Meffert
 132    * @since 2.4
 133    */
 134  0 public Chromosome()
 135    throws InvalidConfigurationException {
 136  0 super(Genotype.getStaticConfiguration());
 137    }
 138   
 139    /**
 140    * Default constructor, provided for dynamic instantiation.
 141    * @param a_configuration the configuration to use
 142    * @throws InvalidConfigurationException
 143    *
 144    * @author Klaus Meffert
 145    * @since 3.0
 146    */
 147  20 public Chromosome(final Configuration a_configuration)
 148    throws InvalidConfigurationException {
 149  20 super(a_configuration);
 150    }
 151   
 152    /**
 153    * Constructor for specifying the number of genes.
 154    * @param a_configuration the configuration to use
 155    * @param a_desiredSize number of genes the chromosome contains of
 156    * @throws InvalidConfigurationException
 157    *
 158    * @author Klaus Meffert
 159    * @since 2.2
 160    */
 161  28079 public Chromosome(final Configuration a_configuration,
 162    final int a_desiredSize)
 163    throws InvalidConfigurationException {
 164  28079 super(a_configuration);
 165  28079 if (a_desiredSize <= 0) {
 166  9 throw new IllegalArgumentException(
 167    "Chromosome size must be greater than zero");
 168    }
 169  28070 m_genes = new Gene[a_desiredSize];
 170    }
 171   
 172    /**
 173    * Constructs a Chromosome of the given size separate from any specific
 174    * Configuration. This constructor will use the given sample Gene to
 175    * construct a new Chromosome instance containing genes all of the same
 176    * type as the sample Gene. This can be useful for constructing sample
 177    * chromosomes that use the same Gene type for all of their genes and that
 178    * are to be used to setup a Configuration object.
 179    *
 180    * @param a_configuration the configuration to use
 181    * @param a_sampleGene a concrete sampleGene instance that will be used
 182    * as a template for all of the genes in this Chromosome
 183    * @param a_desiredSize the desired size (number of genes) of this Chromosome
 184    * @throws InvalidConfigurationException
 185    *
 186    * @author Neil Rotstan
 187    * @author Klaus Meffert
 188    * @since 1.0
 189    */
 190  1213 public Chromosome(final Configuration a_configuration,
 191    final Gene a_sampleGene, final int a_desiredSize)
 192    throws InvalidConfigurationException {
 193  1213 this(a_configuration, a_desiredSize);
 194  1213 initFromGene(a_sampleGene);
 195    }
 196   
 197  3 public Chromosome(final Configuration a_configuration, Gene a_sampleGene,
 198    int a_desiredSize,
 199    IGeneConstraintChecker a_constraintChecker)
 200    throws InvalidConfigurationException {
 201  3 this(a_configuration, a_desiredSize);
 202  3 initFromGene(a_sampleGene);
 203  2 setConstraintChecker(a_constraintChecker);
 204    }
 205   
 206  1216 protected void initFromGene(Gene a_sampleGene) {
 207    // Do sanity checking to make sure the parameters we were
 208    // given are valid.
 209    // ------------------------------------------------------
 210  1216 if (a_sampleGene == null) {
 211  2 throw new IllegalArgumentException(
 212    "Sample Gene cannot be null.");
 213    }
 214    // Populate the array of genes it with new Gene instances
 215    // created from the sample gene.
 216    // ------------------------------------------------------
 217  1214 for (int i = 0; i < m_genes.length; i++) {
 218  11455 m_genes[i] = a_sampleGene.newGene();
 219    }
 220    }
 221   
 222    /**
 223    * Constructs a Chromosome separate from any specific Configuration. This
 224    * can be useful for constructing sample chromosomes that are to be used
 225    * to setup a Configuration object.
 226    *
 227    * @param a_configuration the configuration to use
 228    * @param a_initialGenes the initial genes of this Chromosome
 229    * @throws InvalidConfigurationException
 230    *
 231    * @author Neil Rotstan
 232    * @since 1.0
 233    */
 234  26847 public Chromosome(final Configuration a_configuration, Gene[] a_initialGenes)
 235    throws InvalidConfigurationException {
 236  26847 this(a_configuration, a_initialGenes == null ? 0 : a_initialGenes.length);
 237  26847 checkGenes(a_initialGenes);
 238  26845 m_genes = a_initialGenes;
 239    }
 240   
 241    /**
 242    * Constructs a Chromosome separate from any specific Configuration. This
 243    * can be useful for constructing sample chromosomes that are to be used
 244    * to setup a Configuration object. Additionally, a constraint checker can be
 245    * specified. It is used right here to verify the validity of the gene types
 246    * supplied.
 247    *
 248    * @param a_configuration the configuration to use
 249    * @param a_initialGenes the initial genes of this Chromosome
 250    * @param a_constraintChecker constraint checker to use
 251    * @throws InvalidConfigurationException in case the constraint checker
 252    * reports a configuration error
 253    *
 254    * @author Klaus Meffert
 255    * @since 2.5
 256    */
 257  0 public Chromosome(final Configuration a_configuration, Gene[] a_initialGenes,
 258    IGeneConstraintChecker a_constraintChecker)
 259    throws InvalidConfigurationException {
 260  0 this(a_configuration, a_initialGenes.length);
 261  0 checkGenes(a_initialGenes);
 262  0 m_genes = a_initialGenes;
 263  0 setConstraintChecker(a_constraintChecker);
 264    }
 265   
 266    /**
 267    * Helper: called by constructors only to verify the initial genes.
 268    * @param a_initialGenes the initial genes of this Chromosome to verify
 269    *
 270    * @author Klaus Meffert
 271    * @since 2.5
 272    */
 273  26847 protected void checkGenes(Gene[] a_initialGenes) {
 274    // Sanity checks: make sure the genes array isn't null and
 275    // that none of the genes contained within it are null.
 276    // Check against null already done in constructors!
 277    // -------------------------------------------------------
 278  26847 for (int i = 0; i < a_initialGenes.length; i++) {
 279  99088 if (a_initialGenes[i] == null) {
 280  2 throw new IllegalArgumentException(
 281    "The gene at index " + i + " in the given array of " +
 282    "genes was found to be null. No gene in the array " +
 283    "may be null.");
 284    }
 285    }
 286    }
 287   
 288    /**
 289    * Returns a copy of this Chromosome. The returned instance can evolve
 290    * independently of this instance. Note that, if possible, this method
 291    * will first attempt to acquire a Chromosome instance from the active
 292    * ChromosomePool (if any) and set its value appropriately before
 293    * returning it. If that is not possible, then a new Chromosome instance
 294    * will be constructed and its value set appropriately before returning.
 295    *
 296    * @return copy of this Chromosome
 297    * @throws IllegalStateException instead of CloneNotSupportedException
 298    *
 299    * @author Neil Rotstan
 300    * @author Klaus Meffert
 301    * @since 1.0
 302    */
 303  4136 public synchronized Object clone() {
 304    // Before doing anything, make sure that a Configuration object
 305    // has been set on this Chromosome. If not, then throw an
 306    // IllegalStateException.
 307    // ------------------------------------------------------------
 308  4136 if (getConfiguration() == null) {
 309  0 throw new IllegalStateException(
 310    "The active Configuration object must be set on this " +
 311    "Chromosome prior to invocation of the clone() method.");
 312    }
 313  4136 IChromosome copy = null;
 314    // Now, first see if we can pull a Chromosome from the pool and just
 315    // set its gene values (alleles) appropriately.
 316    // ------------------------------------------------------------
 317  4136 IChromosomePool pool = getConfiguration().getChromosomePool();
 318  4136 if (pool != null) {
 319  4036 copy = pool.acquireChromosome();
 320  4036 if (copy != null) {
 321  2 Gene[] genes = copy.getGenes();
 322  2 for (int i = 0; i < size(); i++) {
 323  2 genes[i].setAllele(m_genes[i].getAllele());
 324    }
 325    }
 326    }
 327  4136 try {
 328  4136 if (copy == null) {
 329    // We couldn't fetch a Chromosome from the pool, so we need to create
 330    // a new one. First we make a copy of each of the Genes. We explicity
 331    // use the Gene at each respective gene location (locus) to create the
 332    // new Gene that is to occupy that same locus in the new Chromosome.
 333    // -------------------------------------------------------------------
 334  4134 int size = size();
 335  4134 if (size > 0) {
 336  4133 Gene[] copyOfGenes = new Gene[size];
 337  4133 for (int i = 0; i < copyOfGenes.length; i++) {
 338  28051 copyOfGenes[i] = m_genes[i].newGene();
 339  28051 copyOfGenes[i].setAllele(m_genes[i].getAllele());
 340    }
 341    // Now construct a new Chromosome with the copies of the genes and
 342    // return it. Also clone the IApplicationData object.
 343    // ---------------------------------------------------------------
 344    /**@todo clone Config!*/
 345  4133 copy = new Chromosome(getConfiguration(), copyOfGenes);
 346    }
 347    else {
 348  1 copy = new Chromosome(getConfiguration());
 349    }
 350    }
 351    // Clone constraint checker.
 352    // -------------------------
 353  4136 copy.setConstraintChecker(getConstraintChecker());
 354    }
 355    catch (InvalidConfigurationException iex) {
 356  0 throw new IllegalStateException(iex.getMessage());
 357    }
 358    // Also clone the IApplicationData object.
 359    // ---------------------------------------
 360  4136 try {
 361  4136 copy.setApplicationData(cloneObject(getApplicationData()));
 362    }
 363    catch (Exception ex) {
 364  0 throw new IllegalStateException(ex.getMessage());
 365    }
 366  4136 return copy;
 367    }
 368   
 369    /**
 370    * Clones an object by using clone handlers. If no deep cloning possible, then
 371    * return the reference.
 372    * @param a_object the object to clone
 373    * @return the cloned object, or the object itself if no coning supported
 374    * @throws Exception
 375    *
 376    * @author Klaus Meffert
 377    * @since 2.6
 378    */
 379  4136 protected Object cloneObject(Object a_object)
 380    throws Exception {
 381  4136 if (a_object == null) {
 382  4134 return null;
 383    }
 384    // Try to clone via a registered clone handler.
 385    // --------------------------------------------
 386  2 ICloneHandler cloner = getConfiguration().getJGAPFactory().
 387    getCloneHandlerFor(a_object, a_object.getClass());
 388  2 if (cloner != null) {
 389  2 return cloner.perform(a_object, null, this);
 390    }
 391    else {
 392    // No cloning supported, so just return the reference.
 393    // ---------------------------------------------------
 394  0 return a_object;
 395    }
 396    }
 397   
 398    /**
 399    * Returns the Gene at the given index (locus) within the Chromosome. The
 400    * first gene is at index zero and the last gene is at the index equal to
 401    * the size of this Chromosome - 1.
 402    *
 403    * @param a_desiredLocus index of the gene value to be returned
 404    * @return Gene at the given index
 405    *
 406    * @author Neil Rotstan
 407    * @since 1.0
 408    */
 409  386 public synchronized Gene getGene(int a_desiredLocus) {
 410  386 return m_genes[a_desiredLocus];
 411    }
 412   
 413    /**
 414    * Retrieves the set of genes that make up this Chromosome. This method
 415    * exists primarily for the benefit of GeneticOperators that require the
 416    * ability to manipulate Chromosomes at a low level.
 417    *
 418    * @return an array of the Genes contained within this Chromosome
 419    *
 420    * @author Neil Rotstan
 421    * @since 1.0
 422    */
 423  1688447 public synchronized Gene[] getGenes() {
 424  1688447 return m_genes;
 425    }
 426   
 427    /**
 428    * Returns the size of this Chromosome (the number of genes it contains).
 429    * A Chromosome's size is constant and will not change, until setGenes(...)
 430    * is used.
 431    *
 432    * @return number of genes contained within this Chromosome instance
 433    *
 434    * @author Neil Rotstan
 435    * @author Klaus Meffert
 436    * @since 1.0
 437    */
 438  5132738 public int size() {
 439  5132738 if (m_genes == null) {
 440    // only possible when using default constructor
 441  8 return 0;
 442    }
 443    else {
 444  5132730 return m_genes.length;
 445    }
 446    }
 447   
 448    /**
 449    * Retrieves the fitness value of this Chromosome, as determined by the
 450    * active fitness function. If a bulk fitness function is in use and
 451    * has not yet assigned a fitness value to this Chromosome, then -1 is
 452    * returned.<p>
 453    * Attention: should not be called from toString() as the fitness value would
 454    * be computed if it was initial!
 455    *
 456    * @return a positive double value representing the fitness of this
 457    * Chromosome, or -1 if a bulk fitness function is in use and has not yet
 458    * assigned a fitness value to this Chromosome
 459    *
 460    * @author Neil Rotstan
 461    * @author Klaus Meffert
 462    * @since 2.0 (until 1.1: return type int)
 463    */
 464  65585 public double getFitnessValue() {
 465  65585 if (m_fitnessValue >= 0.000d) {
 466  58822 return m_fitnessValue;
 467    }
 468    else {
 469  6763 return calcFitnessValue();
 470    }
 471    }
 472   
 473    /**
 474    * @return the lastly computed fitness value, or FitnessFunction.NO_FITNESS_VALUE
 475    * in case no value has been computed yet.
 476    *
 477    * @author Klaus Meffert
 478    */
 479  2686 public double getFitnessValueDirectly() {
 480  2686 return m_fitnessValue;
 481    }
 482   
 483    /**
 484    * @return fitness value of this chromosome determined via the registered
 485    * fitness function
 486    *
 487    * @author Klaus Meffert
 488    * @since 2.4
 489    */
 490  6763 protected double calcFitnessValue() {
 491  6763 if (getConfiguration() != null) {
 492  6763 FitnessFunction normalFitnessFunction = getConfiguration().
 493    getFitnessFunction();
 494  6763 if (normalFitnessFunction != null) {
 495    // Grab the "normal" fitness function and ask it to calculate our
 496    // fitness value.
 497    // --------------------------------------------------------------
 498  6697 m_fitnessValue = normalFitnessFunction.getFitnessValue(this);
 499    }
 500    }
 501  6763 return m_fitnessValue;
 502    }
 503   
 504    /**
 505    * Sets the fitness value of this Chromosome. This method is for use
 506    * by bulk fitness functions and should not be invokved from anything
 507    * else (except test cases).
 508    *
 509    * @param a_newFitnessValue a positive integer representing the fitness
 510    * of this Chromosome
 511    *
 512    * @author Neil Rotstan
 513    * @since 1.0
 514    */
 515  8300 public void setFitnessValue(double a_newFitnessValue) {
 516  8300 if (a_newFitnessValue >= 0 &&
 517    Math.abs(m_fitnessValue - a_newFitnessValue) > 0.0000001) {
 518  352 m_fitnessValue = a_newFitnessValue;
 519    }
 520    }
 521   
 522   
 523    /**
 524    * Sets the fitness value of this Chromosome directly without any
 525    * constraint checks, conversions or checks. Only use if you know what
 526    * you do.
 527    *
 528    * @param a_newFitnessValue a positive integer representing the fitness
 529    * of this Chromosome
 530    *
 531    * @author Klaus Meffert
 532    */
 533  3066 public void setFitnessValueDirectly(double a_newFitnessValue) {
 534  3066 m_fitnessValue = a_newFitnessValue;
 535    }
 536   
 537    /**
 538    * @return a string representation of this Chromosome, useful
 539    * for display purposes.
 540    *
 541    * @author Neil Rotstan
 542    * @author Klaus Meffert
 543    * @since 1.0
 544    */
 545  19 public String toString() {
 546  19 StringBuffer representation = new StringBuffer();
 547  19 representation.append(S_SIZE + ":" + size());
 548    // Don't use getFitnessValue() here as it would then be initialized anyway!
 549    // ------------------------------------------------------------------------
 550  19 representation.append(", " + S_FITNESS_VALUE + ":" + m_fitnessValue);
 551  19 representation.append(", " + S_ALLELES + ":");
 552  19 representation.append("[");
 553    // Append the representations of each of the genes' alleles.
 554    // ---------------------------------------------------------
 555  19 for (int i = 0; i < m_genes.length; i++) {
 556  34 if (i > 0) {
 557  15 representation.append(", ");
 558    }
 559  34 if (m_genes[i] == null) {
 560  6 representation.append("null");
 561    }
 562    else {
 563  28 representation.append(m_genes[i].toString());
 564    }
 565    }
 566  19 representation.append("]");
 567  19 String appData;
 568  19 if (getApplicationData() != null) {
 569  1 appData = getApplicationData().toString();
 570    }
 571    else {
 572  18 appData = "null";
 573    }
 574  19 representation.append(", " + S_APPLICATION_DATA + ":" + appData);
 575  19 return representation.toString();
 576    }
 577   
 578    /**
 579    * Convenience method that returns a new Chromosome instance with its
 580    * genes values (alleles) randomized. Note that, if possible, this method
 581    * will acquire a Chromosome instance from the active ChromosomePool
 582    * (if any) and then randomize its gene values before returning it. If a
 583    * Chromosome cannot be acquired from the pool, then a new instance will
 584    * be constructed and its gene values randomized before returning it.
 585    *
 586    * @param a_configuration the configuration to use
 587    * @return randomly initialized Chromosome
 588    * @throws InvalidConfigurationException if the given Configuration
 589    * instance is invalid
 590    * @throws IllegalArgumentException if the given Configuration instance
 591    * is null
 592    *
 593    * @author Neil Rotstan
 594    * @since 1.0
 595    */
 596  7948 public static IChromosome randomInitialChromosome(
 597    Configuration a_configuration)
 598    throws InvalidConfigurationException {
 599    // Sanity check: make sure the given configuration isn't null.
 600    // -----------------------------------------------------------
 601  7948 if (a_configuration == null) {
 602  1 throw new IllegalArgumentException(
 603    "Configuration instance must not be null");
 604    }
 605    // Lock the configuration settings so that they can't be changed
 606    // from now on.
 607    // -------------------------------------------------------------
 608  7947 a_configuration.lockSettings();
 609    // First see if we can get a Chromosome instance from the pool.
 610    // If we can, we'll randomize its gene values (alleles) and then
 611    // return it.
 612    // -------------------------------------------------------------
 613  7946 IChromosomePool pool = a_configuration.getChromosomePool();
 614  7946 if (pool != null) {
 615  7794 IChromosome randomChromosome = pool.acquireChromosome();
 616  7794 if (randomChromosome != null) {
 617  1 Gene[] genes = randomChromosome.getGenes();
 618  1 RandomGenerator generator = a_configuration.getRandomGenerator();
 619  1 for (int i = 0; i < genes.length; i++) {
 620  3 genes[i].setToRandomValue(generator);
 621    /**@todo what about Gene's energy?*/
 622    }
 623  1 randomChromosome.setFitnessValueDirectly(FitnessFunction.
 624    NO_FITNESS_VALUE);
 625  1 return randomChromosome;
 626    }
 627    }
 628    // We weren't able to get a Chromosome from the pool, so we have to
 629    // construct a new instance and build it from scratch.
 630    // ------------------------------------------------------------------
 631  7945 IChromosome sampleChromosome =
 632    a_configuration.getSampleChromosome();
 633  7945 sampleChromosome.setFitnessValue(FitnessFunction.NO_FITNESS_VALUE);
 634  7945 Gene[] sampleGenes = sampleChromosome.getGenes();
 635  7945 Gene[] newGenes = new Gene[sampleGenes.length];
 636  7945 RandomGenerator generator = a_configuration.getRandomGenerator();
 637  7945 for (int i = 0; i < newGenes.length; i++) {
 638    // We use the newGene() method on each of the genes in the
 639    // sample Chromosome to generate our new Gene instances for
 640    // the Chromosome we're returning. This guarantees that the
 641    // new Genes are setup with all of the correct internal state
 642    // for the respective gene position they're going to inhabit.
 643    // -----------------------------------------------------------
 644  8334 newGenes[i] = sampleGenes[i].newGene();
 645    // Set the gene's value (allele) to a random value.
 646    // ------------------------------------------------
 647  8334 newGenes[i].setToRandomValue(generator);
 648    /**@todo what about Gene's energy?*/
 649    }
 650    // Finally, construct the new chromosome with the new random
 651    // genes values and return it.
 652    // ---------------------------------------------------------
 653  7945 return new Chromosome(a_configuration, newGenes);
 654    }
 655   
 656    /**
 657    * Compares this Chromosome against the specified object. The result is
 658    * true if and the argument is an instance of the Chromosome class
 659    * and has a set of genes equal to this one.
 660    *
 661    * @param other the object to compare against
 662    * @return true: if the objects are the same, false otherwise
 663    *
 664    * @author Neil Rotstan
 665    * @author Klaus Meffert
 666    * @since 1.0
 667    */
 668  1659970 public boolean equals(Object other) {
 669    // If class is not equal, return false. Therefor catch
 670    // ClasscastException's. The cleaner way (commented out below) would
 671    // be too slow, indeed.
 672    // -----------------------------------------------------------------
 673    /*
 674    if (other != null &&
 675    !this.getClass ().getName ().equals (other.getClass ().getName ()))
 676    {
 677    return false;
 678    }
 679    */
 680  1659970 try {
 681  1659970 return compareTo(other) == 0;
 682    }
 683    catch (ClassCastException cex) {
 684  32262 return false;
 685    }
 686    }
 687   
 688    /**
 689    * Retrieve a hash code for this Chromosome. Does not considers the order
 690    * of the Genes for all cases (especially when gene is empty).
 691    *
 692    * @return the hash code of this Chromosome
 693    *
 694    * @author Neil Rotstan
 695    * @author Klaus Meffert
 696    * @since 1.0
 697    */
 698  5164 public int hashCode() {
 699    // Do what {@link java.util.AbstractList} does.
 700    // --------------------------------------------
 701  5164 int geneHashcode;
 702  5164 int hashCode = 1;
 703  5164 if (m_genes != null) {
 704  5163 for (int i = 0; i < m_genes.length; i++) {
 705  56081 geneHashcode = m_genes[i].hashCode();
 706  56081 hashCode = 31 * hashCode + geneHashcode;
 707    }
 708    }
 709  5164 return hashCode;
 710    }
 711   
 712    /**
 713    * Compares the given Chromosome to this Chromosome. This chromosome is
 714    * considered to be "less than" the given chromosome if it has a fewer
 715    * number of genes or if any of its gene values (alleles) are less than
 716    * their corresponding gene values in the other chromosome.
 717    *
 718    * @param other the Chromosome against which to compare this chromosome
 719    * @return a negative number if this chromosome is "less than" the given
 720    * chromosome, zero if they are equal to each other, and a positive number if
 721    * this chromosome is "greater than" the given chromosome
 722    *
 723    * @author Neil Rotstan
 724    * @author Klaus Meffert
 725    * @since 1.0
 726    */
 727  1660434 public int compareTo(Object other) {
 728    // First, if the other Chromosome is null, then this chromosome is
 729    // automatically the "greater" Chromosome.
 730    // ---------------------------------------------------------------
 731  1660434 if (other == null) {
 732  2 return 1;
 733    }
 734  1660432 int size = size();
 735  1660432 IChromosome otherChromosome = (IChromosome) other;
 736  1660431 Gene[] otherGenes = otherChromosome.getGenes();
 737    // If the other Chromosome doesn't have the same number of genes,
 738    // then whichever has more is the "greater" Chromosome.
 739    // --------------------------------------------------------------
 740  1660431 if (otherChromosome.size() != size) {
 741  884442 return size() - otherChromosome.size();
 742    }
 743    // Next, compare the gene values (alleles) for differences. If
 744    // one of the genes is not equal, then we return the result of its
 745    // comparison.
 746    // ---------------------------------------------------------------
 747  775989 for (int i = 0; i < size; i++) {
 748  1544191 int comparison = m_genes[i].compareTo(otherGenes[i]);
 749  1511930 if (comparison != 0) {
 750  741088 return comparison;
 751    }
 752    }
 753    // Compare current fitness value.
 754    // ------------------------------
 755  2640 if (m_fitnessValue != otherChromosome.getFitnessValueDirectly()) {
 756  19 FitnessEvaluator eval = getConfiguration().getFitnessEvaluator();
 757  19 if (eval != null) {
 758  19 if (eval.isFitter(m_fitnessValue,
 759    otherChromosome.getFitnessValueDirectly())) {
 760  19 return 1;
 761    }
 762    else {
 763  0 return -1;
 764    }
 765    }
 766    else {
 767    // undetermined order, but unequal!
 768    // --------------------------------
 769  0 return -1;
 770    }
 771    }
 772  2621 if (m_compareAppData) {
 773    // Compare application data.
 774    // -------------------------
 775  6 if (getApplicationData() == null) {
 776  3 if (otherChromosome.getApplicationData() != null) {
 777  1 return -1;
 778    }
 779    }
 780  3 else if (otherChromosome.getApplicationData() == null) {
 781  1 return 1;
 782    }
 783    else {
 784  2 if (getApplicationData() instanceof Comparable) {
 785  1 try {
 786  1 return ( (Comparable) getApplicationData()).compareTo(
 787    otherChromosome.getApplicationData());
 788    }
 789    catch (ClassCastException cex) {
 790    /**@todo improve*/
 791  1 return -1;
 792    }
 793    }
 794    else {
 795  1 return getApplicationData().getClass().getName().compareTo(
 796    otherChromosome.getApplicationData().getClass().getName());
 797    }
 798    }
 799    }
 800    // Everything is equal. Return zero.
 801    // ---------------------------------
 802  2617 return 0;
 803    }
 804   
 805    /**
 806    * Sets whether this Chromosome has been selected by the natural selector
 807    * to continue to the next generation or manually (e.g. via an add-method).
 808    *
 809    * @param a_isSelected true if this Chromosome has been selected, false
 810    * otherwise
 811    *
 812    * @author Neil Rotstan
 813    * @since 1.0
 814    */
 815  5541 public void setIsSelectedForNextGeneration(boolean a_isSelected) {
 816  5541 m_isSelectedForNextGeneration = a_isSelected;
 817    }
 818   
 819    /**
 820    * Retrieves whether this Chromosome has been selected by the natural
 821    * selector to continue to the next generation.
 822    *
 823    * @return true if this Chromosome has been selected, false otherwise
 824    *
 825    * @author Neil Rotstan
 826    * @since 1.0
 827    */
 828  2 public boolean isSelectedForNextGeneration() {
 829  2 return m_isSelectedForNextGeneration;
 830    }
 831   
 832    /**
 833    * Invoked when this Chromosome is no longer needed and should perform
 834    * any necessary cleanup. Note that this method will attempt to release
 835    * this Chromosome instance to the active ChromosomePool, if any.
 836    *
 837    * @author Neil Rotstan
 838    * @since 1.0
 839    */
 840  5 public void cleanup() {
 841  5 if (getConfiguration() == null) {
 842  0 throw new IllegalStateException(
 843    "The active Configuration object must be set on this " +
 844    "Chromosome prior to invocation of the cleanup() method.");
 845    }
 846    // First, reset our internal state.
 847    // --------------------------------
 848  5 m_fitnessValue = getConfiguration().getFitnessFunction().
 849    NO_FITNESS_VALUE;
 850  5 m_isSelectedForNextGeneration = false;
 851    // Next we want to try to release this Chromosome to a ChromosomePool
 852    // if one has been setup so that we can save a little time and memory
 853    // next time a Chromosome is needed.
 854    // ------------------------------------------------------------------
 855    // Now fetch the active ChromosomePool from the Configuration object
 856    // and, if the pool exists, release this Chromosome to it.
 857    // -----------------------------------------------------------------
 858  5 IChromosomePool pool = getConfiguration().getChromosomePool();
 859  5 if (pool != null) {
 860    // Note that the pool will take care of any gene cleanup for us,
 861    // so we don't need to worry about it here.
 862    // -------------------------------------------------------------
 863  4 pool.releaseChromosome(this);
 864    }
 865    else {
 866    // No pool is available, so we need to finish cleaning up, which
 867    // basically entails requesting each of our genes to clean
 868    // themselves up as well.
 869    // -------------------------------------------------------------
 870  1 for (int i = 0; i < size(); i++) {
 871  3 m_genes[i].cleanup();
 872    }
 873    }
 874    }
 875   
 876    /**
 877    * This sets the application-specific data that is attached to this
 878    * Chromosome. Attaching application-specific data may be useful for
 879    * some applications when it comes time to evaluate this Chromosome
 880    * in the fitness function. JGAP ignores this data, except for cloning and
 881    * comparison (latter only if opted in via setCompareApplicationData(..))
 882    *
 883    * @param a_newData the new application-specific data to attach to this
 884    * Chromosome. Should be an instance of IApplicationData
 885    *
 886    * @author Neil Rotstan
 887    * @since 1.1
 888    */
 889  4143 public void setApplicationData(Object a_newData) {
 890  4143 m_applicationData = a_newData;
 891    }
 892   
 893    /**
 894    * Retrieves the application-specific data that is attached to this
 895    * Chromosome. Attaching application-specific data may be useful for
 896    * some applications when it comes time to evaluate this Chromosome
 897    * in the fitness function. JGAP ignores this data functionally.
 898    *
 899    * @return the application-specific data previously attached to this
 900    * Chromosome, or null if there is no data attached
 901    *
 902    * @author Neil Rotstan
 903    * @since 1.1
 904    */
 905  4177 public Object getApplicationData() {
 906  4177 return m_applicationData;
 907    }
 908   
 909    /**
 910    * Sets the genes for the chromosome.
 911    * @param a_genes the genes to set for the chromosome
 912    *
 913    * @throws InvalidConfigurationException in case constraint checker is
 914    * provided
 915    *
 916    * @author Klaus Meffert
 917    */
 918  4164 public void setGenes(Gene[] a_genes)
 919    throws InvalidConfigurationException {
 920    // for (int i=0;i<a_genes.length;i++) {
 921    // if (a_genes[i]==null) {
 922    // throw new RuntimeException("Gene may not be null!");
 923    // }
 924    // }
 925  4164 m_genes = a_genes;
 926  4164 verify(getConstraintChecker());
 927    }
 928   
 929    /**
 930    * Should we also consider the application data when comparing? Default is
 931    * "false" as "true" means a Chromosome is losing its identity when
 932    * application data is set differently!
 933    *
 934    * @param a_doCompare true: consider application data in method compareTo
 935    *
 936    * @author Klaus Meffert
 937    * @since 2.2
 938    */
 939  7 public void setCompareApplicationData(boolean a_doCompare) {
 940  7 m_compareAppData = a_doCompare;
 941    }
 942   
 943    /*
 944    * @return should we also consider the application data when comparing?
 945    *
 946    * @author Klaus Meffert
 947    * @since 2.2
 948    */
 949  2 public boolean isCompareApplicationData() {
 950  2 return m_compareAppData;
 951    }
 952   
 953    /**
 954    * Sets the constraint checker to be used for this gene whenever method
 955    * setAllele(Object) is called.
 956    *
 957    * @param a_constraintChecker the constraint checker to be set
 958    * @throws InvalidConfigurationException
 959    *
 960    * @author Klaus Meffert
 961    * @since 2.5
 962    */
 963  4147 public void setConstraintChecker(IGeneConstraintChecker a_constraintChecker)
 964    throws InvalidConfigurationException {
 965  4147 verify(a_constraintChecker);
 966  4145 m_geneAlleleChecker = a_constraintChecker;
 967    }
 968   
 969    /**
 970    * @return IGeneConstraintChecker the constraint checker to be used whenever
 971    * method setGenes(Gene[]) is called.
 972    *
 973    * @author Klaus Meffert
 974    * @since 2.5
 975    */
 976  8308 public IGeneConstraintChecker getConstraintChecker() {
 977  8308 return m_geneAlleleChecker;
 978    }
 979   
 980    /**
 981    * Verifies the state of the chromosome. Especially takes care of the
 982    * given constraint checker.
 983    * @param a_constraintChecker the constraint checker to verify
 984    *
 985    * @throws InvalidConfigurationException
 986    *
 987    * @author Klaus Meffert
 988    * @since 2.5
 989    */
 990  8311 protected void verify(IGeneConstraintChecker a_constraintChecker)
 991    throws InvalidConfigurationException {
 992  8311 if (a_constraintChecker != null && getGenes() != null) {
 993  11 int len = getGenes().length;
 994  11 for (int i = 0; i < len; i++) {
 995  14 Gene gene = getGene(i);
 996  14 if (!a_constraintChecker.verify(gene, null, this, i)) {
 997  3 throw new InvalidConfigurationException(
 998    "The gene type "
 999    + gene.getClass().getName()
 1000    + " is not allowed to be used in the chromosome due to the"
 1001    + " constraint checker used.");
 1002    }
 1003    }
 1004    }
 1005    }
 1006   
 1007    // ------------------------------------
 1008    // Begin of IInitializer implementation
 1009    // ------------------------------------
 1010   
 1011    /**{@inheritDoc}*/
 1012  3 public boolean isHandlerFor(Object a_obj, Class a_class) {
 1013  3 if (a_class == Chromosome.class) {
 1014  1 return true;
 1015    }
 1016    else {
 1017  2 return false;
 1018    }
 1019    }
 1020   
 1021    /**{@inheritDoc}*/
 1022  7938 public Object perform(Object a_obj, Class a_class, Object a_params)
 1023    throws Exception {
 1024  7938 return randomInitialChromosome(getConfiguration());
 1025    }
 1026   
 1027    // ----------------------------------
 1028    // End of IInitializer implementation
 1029    // ----------------------------------
 1030  2 public void setMultiObjectives(List a_values) {
 1031  2 if (m_multiObjective == null) {
 1032  1 m_multiObjective = new Vector();
 1033    }
 1034  2 m_multiObjective.clear();
 1035  2 m_multiObjective.addAll(a_values);
 1036    }
 1037   
 1038  3 public List getMultiObjectives() {
 1039  3 return m_multiObjective;
 1040    }
 1041    }