public static Chromosome GetBest(GetFitnessDelegate getFitness, int targetLen, int optimalFitness,
                                         IReadOnlyList <char> geneSet, DisplayDelegate display)
        {
            var bestParent = GenerateParent(geneSet, targetLen, getFitness);

            display(bestParent);

            if (bestParent.Fitness >= optimalFitness)
            {
                return(bestParent);
            }

            while (true)
            {
                var child = Mutate(bestParent, geneSet, getFitness);
                if (bestParent.Fitness >= child.Fitness)
                {
                    continue;
                }
                display(child);
                if (child.Fitness >= optimalFitness)
                {
                    return(child);
                }
                bestParent = child;
            }
        }
        public static Chromosome <TGene, TFitness> GetBest(GetFitnessDelegate getFitness, int targetLen,
                                                           TFitness optimalFitness, IReadOnlyList <TGene> geneSet, DisplayDelegate display,
                                                           MutateGeneDelegate customMutate = null, CreateDelegate customCreate = null, int?maxAge = null)
        {
            Chromosome <TGene, TFitness> FnMutate(Chromosome <TGene, TFitness> parent) =>
            customMutate == null
                    ? Mutate(parent, geneSet, getFitness)
                    : MutateCustom(parent, customMutate, getFitness);

            Chromosome <TGene, TFitness> FnGenerateParent()
            {
                if (customCreate == null)
                {
                    return(GenerateParent(targetLen, geneSet, getFitness));
                }

                var genes = customCreate();

                return(new Chromosome <TGene, TFitness>(genes, getFitness(genes)));
            }

            foreach (var improvement in GetImprovement(FnMutate, FnGenerateParent, maxAge))
            {
                display(improvement);
                if (optimalFitness.CompareTo(improvement.Fitness) <= 0)
                {
                    return(improvement);
                }
            }

            throw new UnauthorizedAccessException();
        }
        private static Chromosome <TGene, TFitness> GenerateParent(int length, IReadOnlyList <TGene> geneSet,
                                                                   GetFitnessDelegate getFitness)
        {
            var genes      = Rand.RandomSample(geneSet, length);
            var fitness    = getFitness(genes);
            var chromosome = new Chromosome <TGene, TFitness>(genes, fitness);

            return(chromosome);
        }
        public static Chromosome <TGene, TFitness> Mutate(Chromosome <TGene, TFitness> parent, IReadOnlyList <TGene> geneSet,
                                                          GetFitnessDelegate getFitness)
        {
            var childGenes   = parent.Genes.ToArray();
            var index        = Rand.Random.Next(parent.Genes.Count);
            var randomSample = Rand.RandomSample(geneSet, 2);
            var newGene      = randomSample[0];
            var alternate    = randomSample[1];

            childGenes[index] = newGene.Equals(childGenes[index]) ? alternate : newGene;
            var fitness = getFitness(childGenes);

            return(new Chromosome <TGene, TFitness>(childGenes, fitness));
        }
        public static Chromosome <TGene, TFitness> GetBest(GetFitnessDelegate getFitness, int targetLen,
                                                           TFitness optimalFitness, TGene[] geneSet, DisplayDelegate display)
        {
            Chromosome <TGene, TFitness> FnMutate(Chromosome <TGene, TFitness> parent) =>
            Mutate(parent, geneSet, getFitness);

            Chromosome <TGene, TFitness> FnGenerateParent() => GenerateParent(targetLen, geneSet, getFitness);

            foreach (var improvment in GetImprovment(FnMutate, FnGenerateParent))
            {
                display(improvment);
                if (optimalFitness.CompareTo(improvment.Fitness) <= 0)
                {
                    return(improvment);
                }
            }

            throw new Exception();
        }
        private static Chromosome <TGene, TFitness> MutateCustom(Chromosome <TGene, TFitness> parent,
                                                                 MutateGeneDelegate customMutate, GetFitnessDelegate getFitness)
        {
            var childGenes = parent.Genes.ToList();

            customMutate(childGenes);
            var fitness = getFitness(childGenes);

            return(new Chromosome <TGene, TFitness>(childGenes, fitness));
        }
        private static Chromosome Mutate(Chromosome parent, IReadOnlyList <char> geneSet, GetFitnessDelegate getFitness)
        {
            var childGenes   = parent.Genes.ToCharArray();
            var index        = Rand.Random.Next(parent.Genes.Length);
            var randomSample = Rand.RandomSample(geneSet, 2);
            var newGene      = randomSample[0];
            var alternate    = randomSample[1];

            childGenes[index] = newGene == childGenes[index] ? alternate : newGene;
            var genes   = new string(childGenes);
            var fitness = getFitness(genes);

            return(new Chromosome(genes, fitness));
        }
        private static Chromosome GenerateParent(IReadOnlyList <char> geneSet, int length, GetFitnessDelegate getFitness)
        {
            var genes = string.Empty;

            while (genes.Length < length)
            {
                var sampleSize = Math.Min(length - genes.Length, geneSet.Count);
                genes += Rand.RandomSample(geneSet, sampleSize);
            }

            var fitness = getFitness(genes);

            return(new Chromosome(genes, fitness));
        }
        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));
        }
        public static Chromosome <TGene, TFitness> GetBest(GetFitnessDelegate getFitness, int targetLen,
                                                           TFitness optimalFitness, IReadOnlyList <TGene> geneSet, DisplayDelegate display,
                                                           MutateGeneDelegate customMutate = null, CreateDelegate customCreate = null, int?maxAge = null,
                                                           int poolSize = 1, CrossoverDelegate crossover = null, int?maxSeconds = null)
        {
            Chromosome <TGene, TFitness> FnMutate(Chromosome <TGene, TFitness> parent) =>
            customMutate == null
                    ? Mutate(parent, geneSet, getFitness)
                    : MutateCustom(parent, customMutate, getFitness);

            Chromosome <TGene, TFitness> FnGenerateParent()
            {
                if (customCreate == null)
                {
                    return(GenerateParent(targetLen, geneSet, getFitness));
                }

                var genes = customCreate();

                return(new Chromosome <TGene, TFitness>(genes, getFitness(genes), Strategy.Create));
            }

            var strategyLookup =
                new Dictionary <Strategy, StrategyDelegate>
            {
                { Strategy.Create, (parentGenes, index, parents) => FnGenerateParent() },
                { Strategy.Mutate, (parentGenes, index, parents) => FnMutate(parentGenes) },
                {
                    Strategy.Crossover, (parentGenes, index, parents) => Crossover(parentGenes.Genes, index,
                                                                                   parents, getFitness, crossover, FnMutate, FnGenerateParent)
                }
            };

            var usedStrategies =
                new List <StrategyDelegate> {
                strategyLookup[Strategy.Mutate]
            };

            if (crossover != null)
            {
                usedStrategies.Add(strategyLookup[Strategy.Crossover]);
            }

            Chromosome <TGene, TFitness> FnNewChild(Chromosome <TGene, TFitness> parent, int index,
                                                    List <Chromosome <TGene, TFitness> > parents) =>
            crossover != null
                    ? Rand.SelectItem(usedStrategies)(parent, index, parents)
                    : FnMutate(parent);

            try
            {
                foreach (var improvement in GetImprovement(FnNewChild, FnGenerateParent, maxAge, poolSize, maxSeconds))
                {
                    display(improvement);
                    var f = strategyLookup[improvement.Strategy];
                    usedStrategies.Add(f);
                    if (optimalFitness.CompareTo(improvement.Fitness) <= 0)
                    {
                        return(improvement);
                    }
                }
            }
            catch (SearchTimeoutException exception)
            {
                display(exception.Improvement);
                return(exception.Improvement);
            }

            throw new UnauthorizedAccessException();
        }
        public static Chromosome <TGene, TFitness> GenerateParent(int length, IReadOnlyList <TGene> geneSet, GetFitnessDelegate getFitness)
        {
            var genes = Rand.RandomSample(geneSet, length).ToArray();
            var fit   = getFitness(genes);

            return(new Chromosome <TGene, TFitness>(genes, fit));
        }