001/* 002 * Java Genetic Algorithm Library (jenetics-7.2.0). 003 * Copyright (c) 2007-2023 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 java.util.Arrays; 023 024import io.jenetics.internal.math.DoubleAdder; 025import io.jenetics.stat.DoubleSummary; 026import io.jenetics.util.BaseSeq; 027import io.jenetics.util.Seq; 028 029/** 030 * The roulette-wheel selector is also known as fitness proportional selector, 031 * but in the <em>Jenetics</em> library it is implemented as probability selector. 032 * The fitness value <i>f<sub>i</sub></i> is used to calculate the selection 033 * probability of individual <i>i</i>. 034 * 035 * @see <a href="http://en.wikipedia.org/wiki/Roulette_wheel_selection"> 036 * Wikipedia: Roulette wheel selection 037 * </a> 038 * 039 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 040 * @since 1.0 041 * @version 5.0 042 */ 043public class RouletteWheelSelector< 044 G extends Gene<?, G>, 045 N extends Number & Comparable<? super N> 046> 047 extends ProbabilitySelector<G, N> 048{ 049 050 public RouletteWheelSelector() { 051 this(false); 052 } 053 054 protected RouletteWheelSelector(final boolean sorted) { 055 super(sorted); 056 } 057 058 @Override 059 protected double[] probabilities( 060 final Seq<Phenotype<G, N>> population, 061 final int count 062 ) { 063 assert population != null : "Population must not be null. "; 064 assert population.nonEmpty() : "Population is empty."; 065 assert count > 0 : "Population to select must be greater than zero. "; 066 067 final double[] fitness = fitnessOf(population); 068 sub(fitness, Math.min(DoubleSummary.min(fitness), 0.0)); 069 final double sum = DoubleAdder.sum(fitness); 070 071 if (eq(sum, 0.0)) { 072 Arrays.fill(fitness, 1.0/population.size()); 073 } else { 074 for (int i = fitness.length; --i >= 0;) { 075 fitness[i] = fitness[i]/sum; 076 } 077 } 078 079 return fitness; 080 } 081 082 private double[] fitnessOf(final BaseSeq<Phenotype<G, N>> population) { 083 final double[] fitness = new double[population.length()]; 084 for (int i = fitness.length; --i >= 0;) { 085 final double fit = population.get(i).fitness().doubleValue(); 086 fitness[i] = Double.isFinite(fit) ? fit : 0.0; 087 } 088 return fitness; 089 } 090 091 private static void sub(final double[] values, final double subtrahend) { 092 if (Double.compare(subtrahend, 0.0) != 0) { 093 for (int i = values.length; --i >= 0;) { 094 values[i] -= subtrahend; 095 } 096 } 097 } 098 099 @Override 100 public String toString() { 101 return getClass().getSimpleName(); 102 } 103 104}