001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.math3.genetics;
018    
019    /**
020     * Individual in a population. Chromosomes are compared based on their fitness.
021     * <p>
022     * The chromosomes are IMMUTABLE, and so their fitness is also immutable and
023     * therefore it can be cached.
024     *
025     * @since 2.0
026     * @version $Id: Chromosome.java 1416643 2012-12-03 19:37:14Z tn $
027     */
028    public abstract class Chromosome implements Comparable<Chromosome>,Fitness {
029        /** Value assigned when no fitness has been computed yet. */
030        private static final double NO_FITNESS = Double.NEGATIVE_INFINITY;
031    
032        /** Cached value of the fitness of this chromosome. */
033        private double fitness = NO_FITNESS;
034    
035        /**
036         * Access the fitness of this chromosome. The bigger the fitness, the better the chromosome.
037         * <p>
038         * Computation of fitness is usually very time-consuming task, therefore the fitness is cached.
039         *
040         * @return the fitness
041         */
042        public double getFitness() {
043            if (this.fitness == NO_FITNESS) {
044                // no cache - compute the fitness
045                this.fitness = fitness();
046            }
047            return this.fitness;
048        }
049    
050        /**
051         * Compares two chromosomes based on their fitness. The bigger the fitness, the better the chromosome.
052         *
053         * @param another another chromosome to compare
054         * @return
055         * <ul>
056         *   <li>-1 if <code>another</code> is better than <code>this</code></li>
057         *   <li>1 if <code>another</code> is worse than <code>this</code></li>
058         *   <li>0 if the two chromosomes have the same fitness</li>
059         * </ul>
060         */
061        public int compareTo(final Chromosome another) {
062            return ((Double)this.getFitness()).compareTo(another.getFitness());
063        }
064    
065        /**
066         * Returns <code>true</code> iff <code>another</code> has the same representation and therefore the same fitness. By
067         * default, it returns false -- override it in your implementation if you need it.
068         *
069         * @param another chromosome to compare
070         * @return true if <code>another</code> is equivalent to this chromosome
071         */
072        protected boolean isSame(final Chromosome another) {
073            return false;
074        }
075    
076        /**
077         * Searches the <code>population</code> for another chromosome with the same representation. If such chromosome is
078         * found, it is returned, if no such chromosome exists, returns <code>null</code>.
079         *
080         * @param population Population to search
081         * @return Chromosome with the same representation, or <code>null</code> if no such chromosome exists.
082         */
083        protected Chromosome findSameChromosome(final Population population) {
084            for (Chromosome anotherChr : population) {
085                if (this.isSame(anotherChr)) {
086                    return anotherChr;
087                }
088            }
089            return null;
090        }
091    
092        /**
093         * Searches the population for a chromosome representing the same solution, and if it finds one,
094         * updates the fitness to its value.
095         *
096         * @param population Population to search
097         */
098        public void searchForFitnessUpdate(final Population population) {
099            Chromosome sameChromosome = findSameChromosome(population);
100            if (sameChromosome != null) {
101                fitness = sameChromosome.getFitness();
102            }
103        }
104    
105    }