Skip to content

Commit

Permalink
Added RankSelection
Browse files Browse the repository at this point in the history
  • Loading branch information
ZviRosenfeld committed Dec 18, 2020
1 parent 568f32a commit d018e11
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ namespace GeneticAlgorithm.UnitTests.SelectionStrategyTests
public class SelectionStrategyTests
{
private const int runs = 3000;
private const double chromosome1Probability = 0.1, chromosome2Probability = 0.3, chromosome3Probability = 0.6;
private const double chromosome1Evaluation = 0.1, chromosome2Evaluation = 0.3, chromosome3Evaluation = 0.6;
private Population population;

[TestInitialize]
public void TestInitialize()
{
population = new [] { chromosome1Probability * 2, chromosome2Probability * 2, chromosome3Probability * 2}.ToPopulation().Evaluate();
population = new [] { chromosome1Evaluation * 2, chromosome2Evaluation * 2, chromosome3Evaluation * 2}.ToPopulation().Evaluate();
}

[TestMethod]
public void RouletteWheelSelection_MostLieklyToChooseBestChromosome()
{
MostLikelyToChooseBestChromosome(new RouletteWheelSelection(), chromosome1Probability,
chromosome2Probability, chromosome3Probability);
MostLikelyToChooseBestChromosome(new RouletteWheelSelection(), chromosome1Evaluation,
chromosome2Evaluation, chromosome3Evaluation);
}

[TestMethod]
Expand All @@ -46,6 +46,31 @@ public void RouletteWheelSelection_IgnoreSomeOfPopulation(int chromosomesToIgnor
public void RouletteWheelSelection_AssertChromosomesAreScattered() =>
AssertChromosomesAreScattered(new RouletteWheelSelection());

[TestMethod]
public void RankSelection_MostLieklyToChooseBestChromosome()
{
MostLikelyToChooseBestChromosome(new RankSelection(), 1.0 / 6.0, 2.0 / 6.0, 3.0 / 6.0);
}

[TestMethod]
public void RankSelection_OnlyUsesLastPopulation() =>
AssertSelectionStrategyUsesLatestPopulation(new RankSelection());

[TestMethod]
[DataRow(0)]
[DataRow(1)]
[DataRow(2)]
[DataRow(3)]
public void RankSelection_IgnoreSomeOfPopulation(int chromosomesToIgnore)
{
var selection = new RankSelection(1 - chromosomesToIgnore / 4.0);
AssertLowestChromosomesAreIgnored(selection, chromosomesToIgnore);
}

[TestMethod]
public void RankSelection_AssertChromosomesAreScattered() =>
AssertChromosomesAreScattered(new RankSelection());

[TestMethod]
[DataRow(-1)]
[DataRow(1.1)]
Expand Down Expand Up @@ -102,8 +127,8 @@ public void TournamentSelection_BadTournamentSize_ThrowException(int tournamentS
[TestMethod]
public void StochasticUniversalSampling_MostLieklyToChooseBestChromosome()
{
MostLikelyToChooseBestChromosome(new StochasticUniversalSampling(), chromosome1Probability,
chromosome2Probability, chromosome3Probability);
MostLikelyToChooseBestChromosome(new StochasticUniversalSampling(), chromosome1Evaluation,
chromosome2Evaluation, chromosome3Evaluation);
}

[TestMethod]
Expand Down Expand Up @@ -141,11 +166,11 @@ private void MostLikelyToChooseBestChromosome(ISelectionStrategy selection, doub
for (int i = 0; i < runs; i++)
{
var chromosome = selection.SelectChromosome();
if (chromosome.Evaluate() == SelectionStrategyTests.chromosome1Probability * 2)
if (chromosome.Evaluate() == SelectionStrategyTests.chromosome1Evaluation * 2)
chromosome1Counter++;
if (chromosome.Evaluate() == SelectionStrategyTests.chromosome2Probability * 2)
if (chromosome.Evaluate() == SelectionStrategyTests.chromosome2Evaluation * 2)
chromosome2Counter++;
if (chromosome.Evaluate() == SelectionStrategyTests.chromosome3Probability * 2)
if (chromosome.Evaluate() == SelectionStrategyTests.chromosome3Evaluation * 2)
chromosome3Counter++;
}

Expand Down
55 changes: 55 additions & 0 deletions GeneticAlgorithm/SelectionStrategies/RankSelection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using GeneticAlgorithm.Exceptions;
using GeneticAlgorithm.Interfaces;
using System;
using System.Linq;

namespace GeneticAlgorithm.SelectionStrategies
{
/// <summary>
/// RankSelection firsts ranks the chromosomes based on their evaluation. The worst will have fitness 1, second worst 2 etc. and the best will have fitness N (number of chromosomes in population).
/// RankSelection is very similar to RouletteWheelSelection, but can lead to slower convergence, because the best chromosomes do not differ so much from other ones.
/// </summary>
public class RankSelection : ISelectionStrategy
{
private ChromosomeEvaluationPair[] SortedPopulation;
private readonly double percentage;

public RankSelection()
{
percentage = 1;
}

/// <param name="percentage">A double between 0 (not including) and 1 (including). If set, the selection will only consider the n-percent best chromosomes (0 means will consider no chromosomes, and 1 means we'll consider all chromosomes).</param>
public RankSelection(double percentage)
{
if (percentage <= 0 || percentage > 1)
throw new GeneticAlgorithmException($"{nameof(percentage)} must be between 0 (not including) and 1 (including). Was {percentage}.");

this.percentage = percentage;
}

public IChromosome SelectChromosome()
{
var randomNumber = ProbabilityUtils.GetRandomDouble();
var sum = 0.0;
var index = -1;
while (sum < randomNumber)
{
index++;
sum += SortedPopulation[index].Evaluation;
}

return SortedPopulation[index].Chromosome;
}

public void SetPopulation(Population population, int requestedChromosomes)
{
population = population.GetBestChromosomes((int)Math.Ceiling(population.Count() * percentage));
SortedPopulation = population.OrderBy(p => p.Evaluation).ToArray();
var n = SortedPopulation.Length;
var ranksSum = (Math.Pow(n, 2) + n) / 2;
for (var i = 0; i < n; i++)
SortedPopulation[i].Evaluation = (i + 1) / ranksSum;
}
}
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ Existing SelectionStrategies:
- [RouletteWheelSelection](/GeneticAlgorithm/SelectionStrategies/RouletteWheelSelection.cs): With RouletteWheelSelection, the chance of choosing a chromosome is equal to the chromosome's fitness divided by the total fitness. In other words, if we have two chromosomes, A and B, where A.Evaluation == 6 and B.Evaluation == 4, there's a 60% change of choosing A, and a 40% change of choosing B.
- [TournamentSelection](/GeneticAlgorithm/SelectionStrategies/TournamentSelection.cs): With TournamentSelection, we choose a random n chromosomes from the population, and of then select the chromosome with the highest evaluation. In TournamentSelection, selection pressure will grow as the tournament size grows. See [this](https://en.wikipedia.org/wiki/Tournament_selection) link for more information.
- [StochasticUniversalSampling](/GeneticAlgorithm/SelectionStrategies/StochasticUniversalSampling.cs): StochasticUniversalSampling (SUS) is very similar to RouletteWheelSelection. For more information look [here](https://en.wikipedia.org/wiki/Stochastic_universal_sampling).
- [RankSelection](/GeneticAlgorithm/SelectionStrategies/RankSelection.cs): RankSelection firsts ranks the chromosomes based on their evaluation. The worst will have fitness 1, second worst 2 etc. and the best will have fitness N (number of chromosomes in population). RankSelection is very similar to RouletteWheelSelection, but can lead to slower convergence, because the best chromosomes do not differ so much from other ones.

You can find examples of ISelectionStrategies [here](/GeneticAlgorithm/SelectionStrategies).

Expand Down

0 comments on commit d018e11

Please sign in to comment.