![JAR search and dependency download from the Maven repository](/logo.png)
smile.gap.Selection Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2010-2020 Haifeng Li. All rights reserved.
*
* Smile is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* Smile is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Smile. If not, see .
******************************************************************************/
package smile.gap;
import smile.math.MathEx;
import java.util.Arrays;
/**
* The way to select chromosomes from the population as parents to crossover.
*
* @author Haifeng Li
*/
public interface Selection {
/**
* Select a chromosome with replacement from the population based on their
* fitness. Note that the population should be in ascending order in terms
* of fitness.
*/
T apply(T[] population);
/**
* Roulette Wheel Selection, also called fitness proportionate selection.
* Parents are selected by the ratio of its fitness to the fitness of
* other members of the current population.
* */
static Selection RouletteWheel() {
return new Selection() {
@Override
public T apply(T[] population) {
int size = population.length;
double worst = population[0].fitness();
if (worst > 0.0) worst = 0.0;
// In Roulete wheel selection, we don't do such scaling in
// general. However, in case of negative fitness socres,
// we need scale them to positive.
double[] fitness = new double[size];
for (int i = 0; i < size; i++) {
fitness[i] = population[i].fitness() - worst;
}
MathEx.unitize1(fitness);
return population[MathEx.random(fitness)];
}
};
}
/**
* Scaled Roulette Wheel Selection. As the average fitness of
* chromosomes in the population increases, the variance of fitness
* decreases in the population. There may be little difference between
* the best and worst chromosome in the population after several
* generations, and the selective pressure based on fitness is
* corresponding reduced. This problem can partially be addressed by
* using some form of fitness scaling. In the simplest case, on can
* subtract the fitness of the worst chromosome in the population
* from the fitnesses of all chromosomes in the population.
* Alternatively, one may use rank based selection.
*/
static Selection ScaledRouletteWheel() {
return new Selection() {
@Override
public T apply(T[] population) {
int size = population.length;
double worst = population[0].fitness();
double[] fitness = new double[size];
for (int i = 0; i < size; i++) {
fitness[i] = population[i].fitness() - worst;
}
MathEx.unitize1(fitness);
return population[MathEx.random(fitness)];
}
};
}
/**
* Rank Selection. The Roulette Wheel Selection will have problems when
* the fitnesses differs very much. For example, if the best chromosome
* fitness is 90% of all the roulette wheel then the other chromosomes
* will have very few chances to be selected. Rank selection first ranks
* the population and then every chromosome receives fitness from this
* ranking. The worst will have fitness 1 and the best will have fitness
* N (number of chromosomes in population). After this all the
* chromosomes have a chance to be selected. But this method can lead
* to slower convergence, because the best chromosomes do not differ
* so much from other ones.
*/
static Selection Rank() {
return new Selection() {
@Override
public T apply(T[] population) {
int size = population.length;
double[] fitness = new double[size];
for (int i = 0; i < size; i++) {
fitness[i] = i + 1;
}
MathEx.unitize1(fitness);
return population[MathEx.random(fitness)];
}
};
}
/**
* Tournament Selection. Tournament selection returns the fittest
* individual of some t individuals picked at random, with replacement,
* from the population. First choose t (the tournament size) individuals
* from the population at random. Then choose the best individual from
* tournament with probability p, choose the second best individual with
* probability p*(1-p), choose the third best individual with
* probability p*((1-p)^2), and so on... Tournament Selection has become
* the primary selection technique used for the Genetic Algorithm.
* First, it's not sensitive to the particulars of the fitness function.
* Second, it's very simple, requires no preprocessing, and works well
* with parallel algorithms. Third, it's tunable: by setting the
* tournament size t, you can change how selective the technique is.
* At the extremes, if t = 1, this is just random search. If t is very
* large (much larger than the population size itself), then the
* probability that the fittest individual in the population will appear
* in the tournament approaches 1.0, and so Tournament Selection just
* picks the fittest individual each time.
*
* @param size the size of tournament pool.
* @param probability the best-player-wins probability.
*/
static Selection Tournament(int size, double probability) {
return new Selection() {
@Override
@SuppressWarnings("unchecked")
public T apply(T[] population) {
Chromosome[] pool = new Chromosome[size];
for (int i = 0; i < size; i++) {
pool[i] = population[MathEx.randomInt(population.length)];
}
Arrays.sort(pool);
for (int i = 1; i <= size; i++) {
double p = MathEx.random();
if (p < probability) {
return (T) pool[size - i];
}
}
return (T) pool[size - 1];
}
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy