Пример #1
0
        //-------------------------------------------------------------------------
        // For each generation, we get information about what's going on
        //-------------------------------------------------------------------------
        private bool PerGenerationCallback(EngineProgress progress)
        {
            string summary = "Generation " + progress.GenerationNumber +
                             " best: " + progress.BestFitnessThisGen.ToString("0") +
                             " avg: " + progress.AvgFitnessThisGen.ToString("0");

            displayGenerationCallback(summary);
            Debug.WriteLine(summary);

            // return true to keep going, false to halt the system
            bool keepRunning = true;

            return(keepRunning);
        }
Пример #2
0
        //-------------------------------------------------------------------------
        // For each generation, we get information about what's going on
        //-------------------------------------------------------------------------
        private bool PerGenerationCallback(EngineProgress progress, CandidateSolution <bool, ProblemState> bestThisGeneration)
        {
            string summary =
                "Upcard " + currentDealerUpcardRank +
                " gen: " + progress.GenerationNumber +
                " best: " + progress.BestFitnessThisGen.ToString("0") +
                " avg: " + progress.AvgFitnessThisGen.ToString("0");

            perGenerationCallback(summary, bestThisGeneration);
            Debug.WriteLine(summary);

            // keep track of how many gens we've searched
            NumGenerationsNeeded++;

            // return true to keep going, false to halt the system
            bool keepRunning = true;

            return(keepRunning);
        }
Пример #3
0
        public Strategy FindBestSolution()
        {
            // this code assumes that a "best" fitness is one with the highest fitness score
            float bestFitnessScoreAllTime = float.MinValue;
            float bestAverageFitnessScore = float.MinValue;
            int   bestSolutionGenerationNumber = 0, bestAverageFitnessGenerationNumber = 0;

            // a list of references to objects in our pool
            List <Strategy> nextGeneration = new List <Strategy>();

            // use a pool of candidates, so we aren't constantly creating and destroying
            pool = new StrategyPool(currentEngineParams.PopulationSize * 2);    // *2 to cover this gen and next

            // elitism
            int numElitesToAdd = (int)(currentEngineParams.ElitismRate * currentEngineParams.PopulationSize);

            // depending on whether elitism is used, or the selection type, we may need to sort candidates by fitness (which is slower)
            bool needToSortByFitness =
                currentEngineParams.SelectionStyle == SelectionStyle.Roulette ||
                currentEngineParams.SelectionStyle == SelectionStyle.Ranked ||
                currentEngineParams.ElitismRate > 0;

            // initialize generation 0 with randomness
            for (int n = 0; n < currentEngineParams.PopulationSize; n++)
            {
                var strategy = pool.GetRandomized();
                currentGeneration.Add(strategy);
            }

            // loop over generations
            Stopwatch stopwatch = new Stopwatch();
            int       currentGenerationNumber = 0;

            while (true)
            {
                stopwatch.Restart();

                // for each candidate, find and store the fitness score
                Parallel.ForEach(currentGeneration, (candidate) =>
                {
                    // calc the fitness by calling the user-supplied function via the delegate
                    candidate.Fitness = FitnessFunction(candidate);
                });

                // now check if we have a new best
                float    bestFitnessScoreThisGeneration = float.MinValue;
                Strategy bestSolutionThisGeneration     = null;
                float    totalFitness = 0;

                foreach (var candidate in currentGeneration)
                {
                    totalFitness += candidate.Fitness;

                    // find best of this generation, update best all-time if needed
                    bool isBestThisGeneration = candidate.Fitness > bestFitnessScoreThisGeneration;
                    if (isBestThisGeneration)
                    {
                        bestFitnessScoreThisGeneration = candidate.Fitness;
                        bestSolutionThisGeneration     = candidate;

                        bool isBestEver = bestFitnessScoreThisGeneration > bestFitnessScoreAllTime;
                        if (isBestEver)
                        {
                            bestFitnessScoreAllTime      = bestFitnessScoreThisGeneration;
                            BestSolution                 = candidate.Clone();
                            bestSolutionGenerationNumber = currentGenerationNumber;
                        }
                    }
                }

                // determine average fitness and store if it's all-time best
                float averageFitness = totalFitness / currentEngineParams.PopulationSize;
                if (averageFitness > bestAverageFitnessScore)
                {
                    bestAverageFitnessGenerationNumber = currentGenerationNumber;
                    bestAverageFitnessScore            = averageFitness;
                }

                // report progress back to the user, and allow them to terminate the loop
                EngineProgress progress = new EngineProgress()
                {
                    GenerationNumber   = currentGenerationNumber,
                    AvgFitnessThisGen  = averageFitness,
                    BestFitnessThisGen = bestFitnessScoreThisGeneration,
                    BestFitnessSoFar   = bestFitnessScoreAllTime,
                    TimeForGeneration  = stopwatch.Elapsed
                };
                bool keepGoing = ProgressCallback(progress, bestSolutionThisGeneration);
                if (!keepGoing)
                {
                    break;              // user signalled to end looping
                }
                // termination conditions
                if (currentGenerationNumber >= currentEngineParams.MinGenerations)
                {
                    // exit the loop if we're not making any progress in our average fitness score or our overall best score
                    if (((currentGenerationNumber - bestAverageFitnessGenerationNumber) >= currentEngineParams.MaxStagnantGenerations) &&
                        ((currentGenerationNumber - bestSolutionGenerationNumber) >= currentEngineParams.MaxStagnantGenerations))
                    {
                        break;
                    }

                    // maxed out?
                    if (currentGenerationNumber >= currentEngineParams.MaxGenerations)
                    {
                        break;
                    }
                }

                // depending on the SelectionStyle, we may need to adjust all candidate's fitness scores
                AdjustFitnessScores(needToSortByFitness);

                // Start building the next generation
                nextGeneration.Clear();

                // Elitism
                var theBest = currentGeneration.Take(numElitesToAdd);
                foreach (var peakPerformer in theBest)
                {
                    nextGeneration.Add(pool.CopyOf(peakPerformer));
                }

                //// if we're doing elitism and the all-time best is from a previous generation, add it
                if ((numElitesToAdd > 0) && (currentGenerationNumber != bestSolutionGenerationNumber))
                {
                    nextGeneration.Add(pool.CopyOf(BestSolution));
                }

                // then do the selection, crossover and mutation to populate the rest of the next generation
                var children = SelectCrossOverAndMutate(currentEngineParams.PopulationSize - nextGeneration.Count);
                nextGeneration.AddRange(children);

                // move to the next generation
                foreach (var strategy in currentGeneration)
                {
                    pool.Release(strategy);
                }
                currentGeneration.Clear();
                currentGeneration.AddRange(nextGeneration);

                currentGenerationNumber++;
            }

            return(BestSolution);
        }