/// <summary> /// Try few times to find an unused pair (unless avoidPairRepetition /// is false. /// </summary> protected override IEnumerable <IGenome> PerformSelection(int nbToSelect) { var result = new IGenome[nbToSelect]; for (int tries = 0; tries < nbOfTriesToAvoidRepetition; tries++) { // Remove the best genomes depending on the number of tries. if (tries != 0 && tries % removeBestIfExceedsTriesCap == 0) { var best = genomeAndFitn.MaxBy(x => x.Value).Key; genomeAndFitn.Remove(best); } // Use a copy of the dictionary so that the sets don't have // repeating genomes. var genomeAndFitnCpy = genomeAndFitn.ToDictionary( x => x.Key, x => x.Value); var fitness = genomeAndFitnCpy.Sum(x => x.Value); for (int i = 0; i < nbToSelect; i++) { var targetFitness = GARandomManager.NextFloat(0, fitness); IGenome target = null; foreach (var pair in genomeAndFitnCpy) { if (targetFitness <= pair.Value) { target = pair.Key; break; } else { targetFitness -= pair.Value; } } Debug.Assert(target != null); fitness -= genomeAndFitnCpy[target]; genomeAndFitnCpy.Remove(target); result[i] = target; } if (!avoidPairRepetition) { return(result); } // Order the set, to make it work for cases like: // (1, 5, 2) and (2, 1, 5). result = result.OrderBy(x => x.Fitness).ToArray(); if (!SetOfGenomesAlreadyUsed(result)) { usedSetsOfGenomes.Add(result); return(result); } } throw new Exception("Too many tries for a selection."); }