Example #1
0
        /// <summary>
        ///  Progresses the optimization by evolving the current population.
        /// </summary>
        /// <returns>The number of generations thus far.</returns>
        public int NewGeneration()
        {
            if (population == null)
            {
                throw new InvalidOperationException("Cannot generate a next" +
                                                    " generation without prior call to StartEvolution!");
            }

            List <Individual> newPopulation = new List <Individual>();

            generationCount++;

            WeightedSampler <Individual> sampler = new WeightedSampler <Individual>();

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();

            // Check the fitness values of the current generation.
            foreach (Individual individual in population)
            {
                if (individual.Fitness < 0)
                {
                    throw new ArgumentOutOfRangeException("solutionFitness function",
                                                          "Negative fitness values are not allowed! Use 0 fitness " +
                                                          "for solutions that should not reproduce.");
                }

                if (individual.Fitness > bestSolution.Fitness)
                {
                    bestSolution = new Individual(individual.DNA, individual.Fitness);
                }

                maxFitness = Math.Max(individual.Fitness, maxFitness);
                minFitness = Math.Min(individual.Fitness, minFitness);
            }

            double averageHealth     = 0;
            double averageBitsSet    = 0;
            double averageAge        = 0;
            int    acceptedTotal     = 0;
            int    acceptedWorse     = 0;
            int    purgedIndividuals = 0;

            // Sort the population by fitness.
            population = population.OrderBy(ind => ind.Fitness).ToArray();

            int index = 0;

            foreach (Individual individual in population)
            {
                index++;
                /// Max and min fitness might have changed, so we need to
                /// normalize the fitnesses again.
                individual.normalizedFitness = normalizeFitness(individual.Fitness);

                averageHealth  += individual.normalizedFitness;
                averageBitsSet += SetBits(individual.DNA);

                // Survival of the fittest (population was ordered by fitness above)
                if (index < 0.5 * populationSize)
                {
                    // Could be slightly more concise, I know.
                    purgedIndividuals++;
                    continue;
                }

                /// This seems to have a good effect on convergence speed.
                /// By only allowing solutions that survived a round of culling
                /// to procreate, the solution quality is kept high.
                if (individual.Age >= 1)
                {
                    sampler.AddEntry(individual, individual.normalizedFitness);
                }
                averageAge += individual.Age;

                individual.Age++;

                // Simulated annealing
                Individual temp     = individual;
                Individual mutation = spawnIndividual(mutateDNA(individual.DNA));
                mutation.Age = individual.Age - 1; // TODO: Investigate.
                if (acceptNewState(individual, mutation))
                {
                    acceptedTotal++;
                    if (mutation.Fitness < individual.Fitness)
                    {
                        acceptedWorse++;
                    }
                    temp = mutation;
                }
                newPopulation.Add(temp);
            }

            /*if (purgedIndividuals == 0)
             *  minFitness = minCurrentFitness;*/

            stopwatch.Stop();
            Console.Write("Evaluation time for " + generationCount + " : ");
            Console.WriteLine(stopwatch.ElapsedMilliseconds + " ms");
            Console.WriteLine("Temperature: " + temperature);
            Console.WriteLine("Average health: " + averageHealth / populationSize);
            Console.WriteLine("Average bits set: " + averageBitsSet / populationSize);
            Console.WriteLine("Average age: " + averageAge / populationSize);
            Console.WriteLine("Accepted new states (all/worse): " + acceptedTotal + "/" + acceptedWorse);
            //Console.WriteLine("Purged individuals: " + purgedIndividuals + "/" + populationSize);
            Console.WriteLine("Sampler entries: " + sampler.EntryCount);

            stopwatch.Restart();

            if (!sampler.CanSample)
            {
                // This is actually a pretty serious problem.
                population = createPopulation();
                Console.WriteLine("Entire population was infertile (Generation " +
                                  generationCount + ").");
                //Debug.Fail("Population went extinct, not good...");
                return(generationCount);
            }

            // Breed population and apply random mutations.
            int dnaResets = 0;

            // Replace purged individuals
            for (int i = 0; i < purgedIndividuals; i++)
            {
                BitArray parent1 = sampler.RandomSample().DNA;
                BitArray parent2 = sampler.RandomSample().DNA;

                BitArray newDNA = combineIndividualsDNA(parent1, parent2);

                newPopulation.Add(spawnIndividual(newDNA));
            }

            population = newPopulation.ToArray();

            // Yeah, I know, out of thin air.
            temperature *= annealingFactor;

            stopwatch.Stop();
            Console.WriteLine("Best value so far: " + (1500 - bestSolution.Fitness));
            Console.WriteLine("------------------");
            Console.Out.Flush();

            return(generationCount);
        }
Example #2
0
        /// <summary>
        ///  Progresses the optimization by evolving the current population.
        /// </summary>
        /// <returns>The number of generations thus far.</returns>
        public int NewGeneration()
        {
            if (population == null)
            {
                throw new InvalidOperationException("Cannot generate a next" +
                                                    " generation without prior call to InitializeEvolution!");
            }

            Individual[] newPopulation = new Individual[populationSize];
            int          newPopIndex   = 0;

            generationCount++;

            WeightedSampler <Individual> sampler = new WeightedSampler <Individual>();

#if DEBUG
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();

            double averageHealth  = 0;
            double averageBitsSet = 0;
            double averageAge     = 0;
            int    acceptedTotal  = 0;
            int    acceptedWorse  = 0;
#endif

            // Sort the population by fitness.
            population = population.OrderBy(ind => ind.Fitness).ToArray();

            int index = 0;
            foreach (Individual individual in population)
            {
                index++;

#if DEBUG
                averageHealth  += 1500 - individual.Fitness;
                averageBitsSet += SetBits(individual.DNA);
#endif

                // Survival of the fittest (population was ordered by fitness above)
                if (index < 0.5 * populationSize)
                {
                    continue;
                }

                /// This seems to have a good effect on convergence speed.
                /// By only allowing solutions that survived a round of culling
                /// to procreate, the solution quality is kept high.
                if (individual.Age >= 1)
                {
                    sampler.AddEntry(individual, individual.Fitness);
                }
#if DEBUG
                averageAge += individual.Age;
#endif

                individual.Age++;

                newPopulation[newPopIndex] = individual;
                newPopIndex++;
            }

            //for (int i = 0; i < newPopIndex; i++)
            Parallel.For(0, newPopIndex, i =>
            {
                Individual temp     = newPopulation[i];
                Individual mutation = spawnIndividual(mutateDNA(temp.DNA));

                // Lowering the age here would lead to faster convergence but would
                // make the population go extinct several times.
                mutation.Age = temp.Age;
                // Mutations have a chance to be rejected based on the fitness loss
                // relative to the non-mutated individual. See explanation above.
                if (acceptNewState(temp, mutation))
                {
#if DEBUG
                    // If you want to measure these for debugging purposes, remove the
                    // parallelization of this loop.
                    //acceptedTotal++;
                    //if (mutation.Fitness < temp.Fitness)
                    //    acceptedWorse++;
#endif
                    temp = mutation;
                }
                newPopulation[i] = temp;
            });

#if DEBUG
            stopwatch.Stop();
            //Console.Write("Evaluation time for " + generationCount + " : ");
            //Console.WriteLine(stopwatch.ElapsedMilliseconds + " ms");
            //Console.WriteLine("Average health: " + averageHealth / populationSize);
            //Console.WriteLine("Average bits set: " + averageBitsSet / populationSize);
            //Console.WriteLine("Average age: " + averageAge / populationSize);
            //Console.WriteLine("Accepted new states (all/worse): " + acceptedTotal + "/" + acceptedWorse);
            //Console.WriteLine("Sampler entries: " + sampler.EntryCount);

            stopwatch.Restart();
#endif

            if (!sampler.CanSample)
            {
                // This is actually a pretty serious problem.
                population = createPopulation();
                Console.WriteLine("Entire population was infertile (Generation " +
                                  generationCount + ").");
                //Debug.Fail("Population went extinct, not good...");
                return(generationCount);
            }

            // Replace purged individuals
            //for (int i = newPopIndex; i < populationSize; i++)
            Parallel.For(newPopIndex, populationSize, i =>
            {
                BitArray parent1 = sampler.RandomSample().DNA;
                BitArray parent2 = sampler.RandomSample().DNA;

                BitArray newDNA = combineIndividualsDNA(parent1, parent2);

                newPopulation[i] = spawnIndividual(newDNA);
            });

            population = newPopulation;

            // Doing this at the end so the last generation has a use.
            updateBestSolution();

#if DEBUG
            stopwatch.Stop();
            //Console.WriteLine("Best value so far: " + (1500 - bestSolution.Fitness));
            //Console.WriteLine("------------------");
            //Console.Out.Flush();
#endif

            return(generationCount);
        }