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.ArrayList;
020    import java.util.Collection;
021    import java.util.Collections;
022    import java.util.Iterator;
023    import java.util.List;
024    
025    import org.apache.commons.math3.exception.util.LocalizedFormats;
026    import org.apache.commons.math3.exception.NotPositiveException;
027    import org.apache.commons.math3.exception.NullArgumentException;
028    import org.apache.commons.math3.exception.NumberIsTooLargeException;
029    import org.apache.commons.math3.exception.NumberIsTooSmallException;
030    
031    /**
032     * Population of chromosomes represented by a {@link List}.
033     *
034     * @since 2.0
035     * @version $Id: ListPopulation.java 1422195 2012-12-15 06:45:18Z psteitz $
036     */
037    public abstract class ListPopulation implements Population {
038    
039        /** List of chromosomes */
040        private List<Chromosome> chromosomes;
041    
042        /** maximal size of the population */
043        private int populationLimit;
044    
045        /**
046         * Creates a new ListPopulation instance and initializes its inner chromosome list.
047         *
048         * @param populationLimit maximal size of the population
049         * @throws NotPositiveException if the population limit is not a positive number (&lt; 1)
050         */
051        public ListPopulation(final int populationLimit) throws NotPositiveException {
052            this(Collections.<Chromosome> emptyList(), populationLimit);
053        }
054    
055        /**
056         * Creates a new ListPopulation instance.
057         * <p>
058         * Note: the chromosomes of the specified list are added to the population.
059         *
060         * @param chromosomes list of chromosomes to be added to the population
061         * @param populationLimit maximal size of the population
062         * @throws NullArgumentException if the list of chromosomes is {@code null}
063         * @throws NotPositiveException if the population limit is not a positive number (&lt; 1)
064         * @throws NumberIsTooLargeException if the list of chromosomes exceeds the population limit
065         */
066        public ListPopulation(final List<Chromosome> chromosomes, final int populationLimit)
067            throws NullArgumentException, NotPositiveException, NumberIsTooLargeException {
068    
069            if (chromosomes == null) {
070                throw new NullArgumentException();
071            }
072            if (populationLimit <= 0) {
073                throw new NotPositiveException(LocalizedFormats.POPULATION_LIMIT_NOT_POSITIVE, populationLimit);
074            }
075            if (chromosomes.size() > populationLimit) {
076                throw new NumberIsTooLargeException(LocalizedFormats.LIST_OF_CHROMOSOMES_BIGGER_THAN_POPULATION_SIZE,
077                                                    chromosomes.size(), populationLimit, false);
078            }
079            this.populationLimit = populationLimit;
080            this.chromosomes = new ArrayList<Chromosome>(populationLimit);
081            this.chromosomes.addAll(chromosomes);
082        }
083    
084        /**
085         * Sets the list of chromosomes.
086         * <p>
087         * Note: this method removed all existing chromosomes in the population and adds all chromosomes
088         * of the specified list to the population.
089         *
090         * @param chromosomes the list of chromosomes
091         * @throws NullArgumentException if the list of chromosomes is {@code null}
092         * @throws NumberIsTooLargeException if the list of chromosomes exceeds the population limit
093         * @deprecated use {@link #addChromosomes(Collection)} instead
094         */
095        @Deprecated
096        public void setChromosomes(final List<Chromosome> chromosomes)
097            throws NullArgumentException, NumberIsTooLargeException {
098    
099            if (chromosomes == null) {
100                throw new NullArgumentException();
101            }
102            if (chromosomes.size() > populationLimit) {
103                throw new NumberIsTooLargeException(LocalizedFormats.LIST_OF_CHROMOSOMES_BIGGER_THAN_POPULATION_SIZE,
104                                                    chromosomes.size(), populationLimit, false);
105            }
106            this.chromosomes.clear();
107            this.chromosomes.addAll(chromosomes);
108        }
109    
110        /**
111         * Add a {@link Collection} of chromosomes to this {@link Population}.
112         * @param chromosomeColl a {@link Collection} of chromosomes
113         * @throws NumberIsTooLargeException if the population would exceed the population limit when
114         * adding this chromosome
115         * @since 3.1
116         */
117        public void addChromosomes(final Collection<Chromosome> chromosomeColl) throws NumberIsTooLargeException {
118            if (chromosomes.size() + chromosomeColl.size() > populationLimit) {
119                throw new NumberIsTooLargeException(LocalizedFormats.LIST_OF_CHROMOSOMES_BIGGER_THAN_POPULATION_SIZE,
120                                                    chromosomes.size(), populationLimit, false);
121            }
122            this.chromosomes.addAll(chromosomeColl);
123        }
124    
125        /**
126         * Returns an unmodifiable list of the chromosomes in this population.
127         * @return the unmodifiable list of chromosomes
128         */
129        public List<Chromosome> getChromosomes() {
130            return Collections.unmodifiableList(chromosomes);
131        }
132    
133        /**
134         * Access the list of chromosomes.
135         * @return the list of chromosomes
136         * @since 3.1
137         */
138        protected List<Chromosome> getChromosomeList() {
139            return chromosomes;
140        }
141    
142        /**
143         * Add the given chromosome to the population.
144         *
145         * @param chromosome the chromosome to add.
146         * @throws NumberIsTooLargeException if the population would exceed the {@code populationLimit} after
147         *   adding this chromosome
148         */
149        public void addChromosome(final Chromosome chromosome) throws NumberIsTooLargeException {
150            if (chromosomes.size() >= populationLimit) {
151                throw new NumberIsTooLargeException(LocalizedFormats.LIST_OF_CHROMOSOMES_BIGGER_THAN_POPULATION_SIZE,
152                                                    chromosomes.size(), populationLimit, false);
153            }
154            this.chromosomes.add(chromosome);
155        }
156    
157        /**
158         * Access the fittest chromosome in this population.
159         * @return the fittest chromosome.
160         */
161        public Chromosome getFittestChromosome() {
162            // best so far
163            Chromosome bestChromosome = this.chromosomes.get(0);
164            for (Chromosome chromosome : this.chromosomes) {
165                if (chromosome.compareTo(bestChromosome) > 0) {
166                    // better chromosome found
167                    bestChromosome = chromosome;
168                }
169            }
170            return bestChromosome;
171        }
172    
173        /**
174         * Access the maximum population size.
175         * @return the maximum population size.
176         */
177        public int getPopulationLimit() {
178            return this.populationLimit;
179        }
180    
181        /**
182         * Sets the maximal population size.
183         * @param populationLimit maximal population size.
184         * @throws NotPositiveException if the population limit is not a positive number (&lt; 1)
185         * @throws NumberIsTooSmallException if the new population size is smaller than the current number
186         *   of chromosomes in the population
187         */
188        public void setPopulationLimit(final int populationLimit) throws NotPositiveException, NumberIsTooSmallException {
189            if (populationLimit <= 0) {
190                throw new NotPositiveException(LocalizedFormats.POPULATION_LIMIT_NOT_POSITIVE, populationLimit);
191            }
192            if (populationLimit < chromosomes.size()) {
193                throw new NumberIsTooSmallException(populationLimit, chromosomes.size(), true);
194            }
195            this.populationLimit = populationLimit;
196        }
197    
198        /**
199         * Access the current population size.
200         * @return the current population size.
201         */
202        public int getPopulationSize() {
203            return this.chromosomes.size();
204        }
205    
206        /**
207         * {@inheritDoc}
208         */
209        @Override
210        public String toString() {
211            return this.chromosomes.toString();
212        }
213    
214        /**
215         * Returns an iterator over the unmodifiable list of chromosomes.
216         * <p>Any call to {@link Iterator#remove()} will result in a {@link UnsupportedOperationException}.</p>
217         *
218         * @return chromosome iterator
219         */
220        public Iterator<Chromosome> iterator() {
221            return getChromosomes().iterator();
222        }
223    }