/// <summary>
        ///     Runs the initialization algorithm until the specified number of viable genomes (i.e. genomes that meets the minimal
        ///     criteria) are found and returns those genomes along with the total number of evaluations that were executed to find
        ///     them.
        /// </summary>
        /// <param name="totalEvaluations">The resulting number of evaluations to find the viable seed genomes.</param>
        /// <param name="maxEvaluations">
        ///     The maximum number of evaluations that can be executed before the initialization process
        ///     is restarted.  This prevents getting stuck for a long time and/or ending up with unecessarily complex networks.
        /// </param>
        /// <param name="restartCount">
        ///     The number of times the initialization process has been restarted (this is only used for
        ///     status logging purposes).
        /// </param>
        /// <returns>The list of seed genomes that meet the minimal criteria.</returns>
        public override List <NeatGenome> RunEvolution(out ulong totalEvaluations, uint?maxEvaluations,
                                                       uint restartCount)
        {
            // Create list of viable genomes
            List <NeatGenome> viableGenomes = new List <NeatGenome>(MinSuccessfulAgentCount + MinUnsuccessfulAgentCount);

            do
            {
                Console.Out.WriteLine("Starting up the algorithm on restart #{0}", restartCount);

                // Start the algorithm
                InitializationEa.StartContinue();

                Console.Out.WriteLine("Going into algorithm wait loop...");

                // Ping for status every few hundred milliseconds
                while (RunState.Terminated != InitializationEa.RunState &&
                       RunState.Paused != InitializationEa.RunState)
                {
                    if (InitializationEa.CurrentEvaluations >= maxEvaluations)
                    {
                        // Record the total number of evaluations
                        totalEvaluations = InitializationEa.CurrentEvaluations;

                        // Halt the EA worker thread
                        InitializationEa.RequestPauseAndWait();

                        // Null out the EA and delete the thread
                        // (it's necessary to null out these resources so that the thread will be completely garbage collected)
                        InitializationEa.Reset();
                        InitializationEa = null;

                        // Note that the calling experiment must be able to handle this null return value (not great practice)
                        return(null);
                    }

                    Thread.Sleep(200);
                }

                Console.Out.WriteLine("Attempting to extract viable genome from list...");

                // Add all of the genomes that have solved the maze
                viableGenomes.AddRange(
                    InitializationEa.GenomeList.Where(
                        genome =>
                        genome.EvaluationInfo != null &&
                        genome.EvaluationInfo.ObjectiveDistance < MinSuccessDistance)
                    .Take(MinSuccessfulAgentCount));

                Console.Out.WriteLine("Extracted [{0}] of [{1}] viable genomes in [{2}] evaluations",
                                      viableGenomes.Count, MinSuccessfulAgentCount, InitializationEa.CurrentEvaluations);
            } while (viableGenomes.Count < MinSuccessfulAgentCount);

            // Add the remainder of genomes who have not solved the maze
            // (note that the intuition for doing this after the loop is that most will not have solved)
            viableGenomes.AddRange(
                InitializationEa.GenomeList.Where(
                    genome =>
                    genome.EvaluationInfo != null &&
                    genome.EvaluationInfo.ObjectiveDistance > MinSuccessDistance)
                .Take(MinUnsuccessfulAgentCount));

            // Ensure that the above statement was able to get the required number of unsuccessful agent genomes
            if (viableGenomes.Count(genome => genome.EvaluationInfo.ObjectiveDistance > MinSuccessDistance) <
                MinUnsuccessfulAgentCount)
            {
                throw new SharpNeatException(
                          "Novelty search MCC initialization algorithm failed to produce the requisite number of unsuccessful agent genomes.");
            }

            // Set the total number of evaluations that were executed as part of the initialization process
            totalEvaluations = InitializationEa.CurrentEvaluations;

            return(viableGenomes);
        }
Exemple #2
0
        /// <summary>
        ///     Runs the initialization algorithm until the specified number of viable genomes (i.e. genomes that meets the minimal
        ///     criteria) are found and returns those genomes along with the total number of evaluations that were executed to find
        ///     them.
        /// </summary>
        /// <param name="totalEvaluations">The resulting number of evaluations to find the viable seed genomes.</param>
        /// <param name="maxEvaluations">
        ///     The maximum number of evaluations that can be executed before the initialization process
        ///     is restarted.  This prevents getting stuck for a long time and/or ending up with unecessarily complex networks.
        /// </param>
        /// <param name="restartCount">
        ///     The number of times the initialization process has been restarted (this is only used for
        ///     status logging purposes).
        /// </param>
        /// <returns>The list of seed genomes that meet the minimal criteria.</returns>
        public override List <NeatGenome> RunEvolution(out ulong totalEvaluations, uint?maxEvaluations,
                                                       uint restartCount)
        {
            // The minimum fitness for an agent who has solved the maze
            int solvedFitness = MaxDistanceToTarget - MinSuccessDistance;

            // Create list of viable genomes
            List <NeatGenome> viableGenomes = new List <NeatGenome>(MinSuccessfulAgentCount + MinUnsuccessfulAgentCount);

            Console.Out.WriteLine("Starting up the algorithm on restart #{0}", restartCount);

            do
            {
                // Start the algorithm
                InitializationEa.StartContinue();

                // Ping for status every few hundred milliseconds
                while (RunState.Terminated != InitializationEa.RunState &&
                       RunState.Paused != InitializationEa.RunState)
                {
                    Console.WriteLine(@"Current Evaluations: {0}  Mean Complexity: {1}  Closest Genome Distance: {2}",
                                      InitializationEa.CurrentEvaluations, InitializationEa.Statistics.MeanComplexity,
                                      MaxDistanceToTarget - InitializationEa.Statistics.MaxFitness);

                    if (InitializationEa.CurrentEvaluations >= maxEvaluations)
                    {
                        // Record the total number of evaluations
                        totalEvaluations = InitializationEa.CurrentEvaluations;

                        // Halt the EA worker thread
                        InitializationEa.RequestPauseAndWait();

                        // Null out the factory/EA and delete the thread
                        // (it's necessary to null out these resources so that the thread will be completely garbage collected)
                        InitializationEa.Reset();
                        InitializationEa = null;

                        // Note that the calling experiment must be able to handle this null return value (not great practice)
                        return(null);
                    }

                    Thread.Sleep(200);
                }

                // Add all of the genomes that have solved the maze
                viableGenomes.AddRange(
                    InitializationEa.GenomeList.Where(genome => genome.EvaluationInfo.Fitness > solvedFitness)
                    .Take(MinSuccessfulAgentCount));
            } while (viableGenomes.Count < MinSuccessfulAgentCount);

            // Add the remainder of genomes who have not solved the maze
            // (note that the intuition for doing this after the loop is that most will not have solved)
            viableGenomes.AddRange(
                InitializationEa.GenomeList.Where(genome => genome.EvaluationInfo.Fitness < solvedFitness)
                .Take(MinUnsuccessfulAgentCount));

            // Ensure that the above statement was able to get the required number of unsuccessful agent genomes
            if (viableGenomes.Count(genome => genome.EvaluationInfo.Fitness < solvedFitness) <
                MinUnsuccessfulAgentCount)
            {
                throw new SharpNeatException(
                          "Fitness MCC initialization algorithm failed to produce the requisite number of unsuccessful agent genomes.");
            }

            // Set the total number of evaluations that were executed as part of the initialization process
            totalEvaluations = InitializationEa.CurrentEvaluations;

            return(viableGenomes);
        }