private static IEnumerable <Chromosome <TGene, TFitness> > GetImprovment(MutateChromosomeDelegate newChild,
                                                                                 GenerateParentDelegate generateParent)
        {
            var bestParent = generateParent();

            yield return(bestParent);

            while (true)
            {
                var child = newChild(bestParent);
                if (bestParent.Fitness.CompareTo(child.Fitness) > 0)
                {
                    continue;
                }
                if (child.Fitness.CompareTo(bestParent.Fitness) <= 0)
                {
                    bestParent = child;
                    continue;
                }

                yield return(child);

                bestParent = child;
            }

            // ReSharper disable once IteratorNeverReturns
        }
        private static Chromosome <TGene, TFitness> Crossover(IReadOnlyList <TGene> parentGenes, int index,
                                                              IList <Chromosome <TGene, TFitness> > parents, GetFitnessDelegate getFitness, CrossoverDelegate crossover,
                                                              MutateChromosomeDelegate mutate, GenerateParentDelegate generateParent)
        {
            var donorIndex = Rand.Random.Next(0, parents.Count);

            if (donorIndex == index)
            {
                donorIndex = (donorIndex + 1) % parents.Count;
            }
            var childGenes = crossover(parentGenes, parents[donorIndex].Genes);

            if (childGenes == null)
            {
                // parent and donor are indistinguishable
                parents[donorIndex] = generateParent();
                return(mutate(parents[index]));
            }

            var fitness = getFitness(childGenes);

            return(new Chromosome <TGene, TFitness>(childGenes, fitness, Strategy.Crossover));
        }
        private static IEnumerable <Chromosome <TGene, TFitness> > GetImprovement(MutateChromosomeDelegate newChild,
                                                                                  GenerateParentDelegate generateParent, int?maxAge = null)
        {
            var bestParent = generateParent();
            var parent     = bestParent;

            yield return(bestParent);

            var historicalFitnesses = new List <TFitness> {
                bestParent.Fitness
            };

            while (true)
            {
                var child = newChild(parent);
                if (parent.Fitness.CompareTo(child.Fitness) > 0)
                {
                    if (maxAge == null)
                    {
                        continue;
                    }

                    parent.Age++;
                    if (parent.Age < maxAge)
                    {
                        continue;
                    }

                    var index = historicalFitnesses.BinarySearch(child.Fitness);
                    if (index < 0)
                    {
                        index = ~index;
                    }
                    var difference        = historicalFitnesses.Count - index;
                    var proportionSimilar = (double)difference / historicalFitnesses.Count;
                    var exp = Math.Exp(-proportionSimilar);
                    if (Rand.Random.NextDouble() < exp)
                    {
                        parent = child;
                        continue;
                    }

                    bestParent.Age = 0;
                    parent         = bestParent;
                    continue;
                }

                if (parent.Fitness.CompareTo(child.Fitness) == 0)
                {
                    child.Age = parent.Age + 1;
                    parent    = child;
                    continue;
                }

                child.Age = 0;
                parent    = child;
                if (bestParent.Fitness.CompareTo(child.Fitness) >= 0)
                {
                    continue;
                }

                bestParent = child;
                historicalFitnesses.Add(bestParent.Fitness);
                yield return(bestParent);
            }

            // ReSharper disable once IteratorNeverReturns
        }