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