/// <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); }
/// <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); }