TruncationSelector.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-4.3.0).
003  * Copyright (c) 2007-2018 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * 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  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019  */
020 package io.jenetics;
021 
022 import static java.lang.Math.min;
023 import static java.lang.String.format;
024 import static java.util.Objects.requireNonNull;
025 import static io.jenetics.internal.util.Hashes.hash;
026 
027 import io.jenetics.util.ISeq;
028 import io.jenetics.util.MSeq;
029 import io.jenetics.util.Seq;
030 
031 /**
032  * In truncation selection individuals are sorted according to their fitness.
033  * Only the n  best individuals are selected. The truncation selection is a very
034  * basic selection algorithm. It has it's strength in fast selecting individuals
035  * in large populations, but is not very often used in practice.
036  *
037  @see <a href="http://en.wikipedia.org/wiki/Truncation_selection">
038  *          Wikipedia: Truncation selection
039  *      </a>
040  *
041  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
042  @since 1.0
043  @version 4.0
044  */
045 public final class TruncationSelector<
046     extends Gene<?, G>,
047     extends Comparable<? super C>
048 >
049     implements Selector<G, C>
050 {
051 
052     private final int _n;
053 
054     /**
055      * Create a new {@code TruncationSelector} object, where the worst selected
056      * individual has rank {@code n}. This means, if you want to select
057      * {@code count} individuals, the worst selected individual has rank
058      * {@code n}. If {@code count > n}, the selected population will contain
059      <em>duplicate</em> individuals.
060      *
061      @since 3.8
062      *
063      @param n the worst rank of the selected individuals
064      @throws IllegalArgumentException if {@code n < 1}
065      */
066     public TruncationSelector(final int n) {
067         if (n < 1) {
068             throw new IllegalArgumentException(format(
069                 "n must be greater or equal 1, but was %d.", n
070             ));
071         }
072 
073         _n = n;
074     }
075 
076     /**
077      * Create a new TruncationSelector object.
078      */
079     public TruncationSelector() {
080         this(Integer.MAX_VALUE);
081     }
082 
083     /**
084      * This method sorts the population in descending order while calculating
085      * the selection probabilities. If the selection size is greater the the
086      * population size, the whole population is duplicated until the desired
087      * sample size is reached.
088      *
089      @throws NullPointerException if the {@code population} or {@code opt} is
090      *         {@code null}.
091      */
092     @Override
093     public ISeq<Phenotype<G, C>> select(
094         final Seq<Phenotype<G, C>> population,
095         final int count,
096         final Optimize opt
097     ) {
098         requireNonNull(population, "Population");
099         requireNonNull(opt, "Optimization");
100         if (count < 0) {
101             throw new IllegalArgumentException(format(
102                 "Selection count must be greater or equal then zero, but was %s",
103                 count
104             ));
105         }
106 
107         final MSeq<Phenotype<G, C>> selection = MSeq
108             .ofLength(population.isEmpty() : count);
109 
110         if (count > && !population.isEmpty()) {
111             final MSeq<Phenotype<G, C>> copy = population.asISeq().copy();
112             copy.sort((a, b->
113                 opt.<C>descending().compare(a.getFitness(), b.getFitness()));
114 
115             int size = count;
116             do {
117                 final int length = min(min(copy.size(), size), _n);
118                 for (int i = 0; i < length; ++i) {
119                     selection.set((count - size+ i, copy.get(i));
120                 }
121 
122                 size -= length;
123             while (size > 0);
124         }
125 
126         return selection.toISeq();
127     }
128 
129     @Override
130     public int hashCode() {
131         return hash(getClass());
132     }
133 
134     @Override
135     public boolean equals(final Object obj) {
136         return obj == this || obj != null && getClass() == obj.getClass();
137     }
138 
139     @Override
140     public String toString() {
141         return getClass().getName();
142     }
143 
144 }