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.util.Objects.requireNonNull; 023 024import io.jenetics.util.ISeq; 025import io.jenetics.util.MSeq; 026import io.jenetics.util.RandomRegistry; 027import io.jenetics.util.Seq; 028 029/** 030 * {@code StochasticUniversalSelector} is a method for selecting a 031 * population according to some given probability in a way that minimizes chance 032 * fluctuations. It can be viewed as a type of roulette game where now we have 033 * P equally spaced points which we spin. 034 * 035 * <p> 036 * <img src="doc-files/StochasticUniversalSelection.svg" width="400" 037 * alt="Selector"> 038 * </p> 039 * 040 * The figure above shows how the stochastic-universal selection works; <i>n</i> 041 * is the number of individuals to select. 042 * 043 * @see <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Stochastic_universal_sampling"> 044 * Wikipedia: Stochastic universal sampling 045 * </a> 046 * 047 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 048 * @since 1.0 049 * @version 5.0 050 */ 051public class StochasticUniversalSelector< 052 G extends Gene<?, G>, 053 N extends Number & Comparable<? super N> 054> 055 extends RouletteWheelSelector<G, N> 056{ 057 058 public StochasticUniversalSelector() { 059 super(true); 060 } 061 062 /** 063 * This method sorts the population in descending order while calculating the 064 * selection probabilities. 065 */ 066 @Override 067 public ISeq<Phenotype<G, N>> select( 068 final Seq<Phenotype<G, N>> population, 069 final int count, 070 final Optimize opt 071 ) { 072 requireNonNull(population, "Population"); 073 if (count < 0) { 074 throw new IllegalArgumentException( 075 "Selection count must be greater or equal then zero, but was " + 076 count 077 ); 078 } 079 080 if (count == 0 || population.isEmpty()) { 081 return ISeq.empty(); 082 } 083 084 final MSeq<Phenotype<G, N>> selection = MSeq.ofLength(count); 085 086 final Seq<Phenotype<G, N>> pop = _sorted 087 ? population.asISeq().copy().sort(POPULATION_COMPARATOR) 088 : population; 089 090 final double[] probabilities = probabilities(pop, count, opt); 091 assert pop.size() == probabilities.length; 092 093 //Calculating the equal spaces random points. 094 final double delta = 1.0/count; 095 final double[] points = new double[count]; 096 points[0] = RandomRegistry.random().nextDouble()*delta; 097 for (int i = 1; i < count; ++i) { 098 points[i] = delta*i; 099 } 100 101 int j = 0; 102 double prop = 0; 103 for (int i = 0; i < count; ++i) { 104 while (points[i] > prop) { 105 prop += probabilities[j]; 106 ++j; 107 } 108 109 selection.set(i, pop.get(j%pop.size())); 110 } 111 112 return selection.toISeq(); 113 } 114 115}