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    import java.util.Collections;
020    import java.util.List;
021    
022    import org.apache.commons.math3.exception.NotPositiveException;
023    import org.apache.commons.math3.exception.NullArgumentException;
024    import org.apache.commons.math3.exception.NumberIsTooLargeException;
025    import org.apache.commons.math3.exception.OutOfRangeException;
026    import org.apache.commons.math3.exception.util.LocalizedFormats;
027    import org.apache.commons.math3.util.FastMath;
028    
029    /**
030     * Population of chromosomes which uses elitism (certain percentage of the best
031     * chromosomes is directly copied to the next generation).
032     *
033     * @version $Id: ElitisticListPopulation.java 1416643 2012-12-03 19:37:14Z tn $
034     * @since 2.0
035     */
036    public class ElitisticListPopulation extends ListPopulation {
037    
038        /** percentage of chromosomes copied to the next generation */
039        private double elitismRate = 0.9;
040    
041        /**
042         * Creates a new {@link ElitisticListPopulation} instance.
043         *
044         * @param chromosomes list of chromosomes in the population
045         * @param populationLimit maximal size of the population
046         * @param elitismRate how many best chromosomes will be directly transferred to the next generation [in %]
047         * @throws NullArgumentException if the list of chromosomes is {@code null}
048         * @throws NotPositiveException if the population limit is not a positive number (< 1)
049         * @throws NumberIsTooLargeException if the list of chromosomes exceeds the population limit
050         * @throws OutOfRangeException if the elitism rate is outside the [0, 1] range
051         */
052        public ElitisticListPopulation(final List<Chromosome> chromosomes, final int populationLimit,
053                                       final double elitismRate)
054            throws NullArgumentException, NotPositiveException, NumberIsTooLargeException, OutOfRangeException {
055    
056            super(chromosomes, populationLimit);
057            setElitismRate(elitismRate);
058    
059        }
060    
061        /**
062         * Creates a new {@link ElitisticListPopulation} instance and initializes its inner chromosome list.
063         *
064         * @param populationLimit maximal size of the population
065         * @param elitismRate how many best chromosomes will be directly transferred to the next generation [in %]
066         * @throws NotPositiveException if the population limit is not a positive number (&lt; 1)
067         * @throws OutOfRangeException if the elitism rate is outside the [0, 1] range
068         */
069        public ElitisticListPopulation(final int populationLimit, final double elitismRate)
070            throws NotPositiveException, OutOfRangeException {
071    
072            super(populationLimit);
073            setElitismRate(elitismRate);
074    
075        }
076    
077        /**
078         * Start the population for the next generation. The <code>{@link #elitismRate}</code>
079         * percents of the best chromosomes are directly copied to the next generation.
080         *
081         * @return the beginnings of the next generation.
082         */
083        public Population nextGeneration() {
084            // initialize a new generation with the same parameters
085            ElitisticListPopulation nextGeneration =
086                    new ElitisticListPopulation(getPopulationLimit(), getElitismRate());
087    
088            final List<Chromosome> oldChromosomes = getChromosomeList();
089            Collections.sort(oldChromosomes);
090    
091            // index of the last "not good enough" chromosome
092            int boundIndex = (int) FastMath.ceil((1.0 - getElitismRate()) * oldChromosomes.size());
093            for (int i = boundIndex; i < oldChromosomes.size(); i++) {
094                nextGeneration.addChromosome(oldChromosomes.get(i));
095            }
096            return nextGeneration;
097        }
098    
099        /**
100         * Sets the elitism rate, i.e. how many best chromosomes will be directly transferred to the next generation [in %].
101         *
102         * @param elitismRate how many best chromosomes will be directly transferred to the next generation [in %]
103         * @throws OutOfRangeException if the elitism rate is outside the [0, 1] range
104         */
105        public void setElitismRate(final double elitismRate) throws OutOfRangeException {
106            if (elitismRate < 0 || elitismRate > 1) {
107                throw new OutOfRangeException(LocalizedFormats.ELITISM_RATE, elitismRate, 0, 1);
108            }
109            this.elitismRate = elitismRate;
110        }
111    
112        /**
113         * Access the elitism rate.
114         * @return the elitism rate
115         */
116        public double getElitismRate() {
117            return this.elitismRate;
118        }
119    
120    }