Skip to content

TournamentSelection AllowWinnerCompeteNextTournament=false not working  #127

@leshacsharp

Description

@leshacsharp

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.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions