-
-
Notifications
You must be signed in to change notification settings - Fork 344
Description
Describe the bug
If the AllowWinnerCompeteNextTournament is set up to false, the TournamentSelector always throw
System.ArgumentOutOfRangeException: The length is 2, but the possible unique values between 0 (inclusive) and 1 (exclusive) are 1. (Parameter 'length')
at GeneticSharp.RandomizationBase.GetUniqueInts(Int32 length, Int32 min, Int32 max)
at GeneticSharp.TournamentSelection.PerformSelectChromosomes(Int32 number, Generation generation)
at GeneticSharp.SelectionBase.SelectChromosomes(Int32 number, Generation generation)
at GeneticSharp.GeneticAlgorithm.SelectParents()
at GeneticSharp.GeneticAlgorithm.EvolveOneGeneration()
at GeneticSharp.GeneticAlgorithm.Resume()
at GeneticSharp.GeneticAlgorithm.Start()
For example,
Population minSize = 10, maxSize=20
TournametSelection size=2, allowWinnerCompeteNextTournament=false
The selector tries to select two chromosomes for comparison, then adds the winner to the result until the population is fully initialized (MinSize). After that, the winner is no longer allowed to participate in further tournaments. The issue arises when the selector attempts to add the 10th chromosome, but it fails because only one individual is available, while two are required for comparison.
GeneticSharp/src/GeneticSharp.Domain/Selections/TournamentSelection.cs
Lines 85 to 101 in b6567e3
| var candidates = generation.Chromosomes.ToList(); | |
| var selected = new List<IChromosome>(); | |
| while (selected.Count < number) | |
| { | |
| var randomIndexes = RandomizationProvider.Current.GetUniqueInts(Size, 0, candidates.Count); | |
| var tournamentWinner = candidates.Where((c, i) => randomIndexes.Contains(i)).OrderByDescending(c => c.Fitness).First(); | |
| selected.Add(tournamentWinner.Clone()); | |
| if (!AllowWinnerCompeteNextTournament) | |
| { | |
| candidates.Remove(tournamentWinner); | |
| } | |
| } | |
| return selected; |
To Reproduce
The exception is thrown on the second generation. The first (initial) proceed without the selection.
Expected behavior
Consider removing the AllowWinnerCompeteNextTournament=false as it useless option. If the selector prevents winning chromosomes from participating the next tournaments, the result population will be without any filtration and will remain the same as before.
Sample code
` private const int PopulationMinSize = 10;
private const int PopulationMaxSize = 20;
private const int MaxGenerationNumber = 10;
private const int TournamentSize = 2;
private const bool AllowWinnerCompeteNextTournament = false;
var chromosome = new TestChromosome();
var population = new Population(PopulationMinSize, PopulationMaxSize, chromosome);
var fitness = new TestFitness();
var selection = new TournamentSelection(TournamentSize, AllowWinnerCompeteNextTournament);
var crossover = new UniformCrossover();
var mutation = new UniformMutation();
var termination = new GenerationNumberTermination(MaxGenerationNumber);
var ga = new GeneticAlgorithm(population,
fitness,
selection,
crossover,
mutation);
ga.Termination = termination;
ga.Start(); `
Version:
3.1.4