/// <summary> /// Create and return a SteadyStateNeatEvolutionAlgorithm object (specific to fitness-based evaluations) ready for /// running the /// NEAT algorithm/search based on the given genome factory and genome list. Various sub-parts of the algorithm are /// also constructed and connected up. /// </summary> /// <param name="genomeFactory">The genome factory from which to generate new genomes</param> /// <param name="genomeList">The current genome population</param> /// <param name="startingEvaluations">The number of evaluations that have been executed prior to the current run.</param> /// <returns>Constructed evolutionary algorithm</returns> public override INeatEvolutionAlgorithm<NeatGenome> CreateEvolutionAlgorithm( IGenomeFactory<NeatGenome> genomeFactory, List<NeatGenome> genomeList, ulong startingEvaluations) { ulong initializationEvaluations; // Instantiate the internal initialization algorithm _mazeNavigationInitializer.InitializeAlgorithm(ParallelOptions, genomeList, CreateGenomeDecoder(), startingEvaluations); // Run the initialization algorithm until the requested number of viable seed genomes are found List<NeatGenome> seedPopulation = _mazeNavigationInitializer.EvolveViableGenomes(SeedGenomeCount, true, out initializationEvaluations); // Create complexity regulation strategy. var complexityRegulationStrategy = ExperimentUtils.CreateComplexityRegulationStrategy(ComplexityRegulationStrategy, Complexitythreshold); // Create the evolution algorithm. AbstractNeatEvolutionAlgorithm<NeatGenome> ea = new QueueingNeatEvolutionAlgorithm<NeatGenome>(NeatEvolutionAlgorithmParameters, new ParallelKMeansClusteringStrategy<NeatGenome>(new ManhattanDistanceMetric(1.0, 0.0, 10.0), ParallelOptions), complexityRegulationStrategy, _batchSize, RunPhase.Primary, (_bridgingMagnitude > 0), false, _evolutionDataLogger, _experimentLogFieldEnableMap); // Create IBlackBox evaluator. IPhenomeEvaluator<IBlackBox, BehaviorInfo> mazeNavigationEvaluator = new MazeNavigationMCSEvaluator(MaxDistanceToTarget, MaxTimesteps, MazeVariant, MinSuccessDistance, _behaviorCharacterizationFactory, _bridgingMagnitude, _bridgingApplications, initializationEvaluations); // Create genome decoder. IGenomeDecoder<NeatGenome, IBlackBox> genomeDecoder = CreateGenomeDecoder(); // IGenomeEvaluator<NeatGenome> fitnessEvaluator = // new SerialGenomeBehaviorEvaluator<NeatGenome, IBlackBox>(genomeDecoder, mazeNavigationEvaluator, // SelectionType.Queueing, SearchType.MinimalCriteriaSearch, _evaluationDataLogger, // SerializeGenomeToXml); IGenomeEvaluator<NeatGenome> fitnessEvaluator = new ParallelGenomeBehaviorEvaluator<NeatGenome, IBlackBox>(genomeDecoder, mazeNavigationEvaluator, SelectionType.Queueing, SearchType.MinimalCriteriaSearch, _evaluationDataLogger, SerializeGenomeToXml); // Initialize the evolution algorithm. ea.Initialize(fitnessEvaluator, genomeFactory, seedPopulation, DefaultPopulationSize, null, MaxEvaluations + startingEvaluations); // Finished. Return the evolution algorithm return ea; }
/// <summary> /// Create and return a SteadyStateNeatEvolutionAlgorithm object (specific to fitness-based evaluations) ready for /// running the /// NEAT algorithm/search based on the given genome factory and genome list. Various sub-parts of the algorithm are /// also constructed and connected up. /// </summary> /// <param name="genomeFactory">The genome factory from which to generate new genomes</param> /// <param name="genomeList">The current genome population</param> /// <param name="startingEvaluations">The number of evaluations that have been executed prior to the current run.</param> /// <returns>Constructed evolutionary algorithm</returns> public override INeatEvolutionAlgorithm<NeatGenome> CreateEvolutionAlgorithm( IGenomeFactory<NeatGenome> genomeFactory, List<NeatGenome> genomeList, ulong startingEvaluations) { // Create complexity regulation strategy. var complexityRegulationStrategy = ExperimentUtils.CreateComplexityRegulationStrategy(ComplexityRegulationStrategy, Complexitythreshold); // Create the evolution algorithm. AbstractNeatEvolutionAlgorithm<NeatGenome> ea = new QueueingNeatEvolutionAlgorithm<NeatGenome>(NeatEvolutionAlgorithmParameters, new ParallelKMeansClusteringStrategy<NeatGenome>(new ManhattanDistanceMetric(1.0, 0.0, 10.0), ParallelOptions), complexityRegulationStrategy, _batchSize, RunPhase.Primary); // Create IBlackBox evaluator. IPhenomeEvaluator<IBlackBox, FitnessInfo> mazeNavigationEvaluator = new MazeNavigationRandomEvaluator(MaxDistanceToTarget, MaxTimesteps, MazeVariant, MinSuccessDistance); // Create genome decoder. IGenomeDecoder<NeatGenome, IBlackBox> genomeDecoder = CreateGenomeDecoder(); IGenomeEvaluator<NeatGenome> fitnessEvaluator = new SerialGenomeFitnessEvaluator<NeatGenome, IBlackBox>(genomeDecoder, mazeNavigationEvaluator, _evaluationDataLogger); // IGenomeEvaluator<NeatGenome> fitnessEvaluator = // new ParallelGenomeFitnessEvaluator<NeatGenome, IBlackBox>(genomeDecoder, mazeNavigationEvaluator, // _evaluationDataLogger, SerializeGenomeToXml); // Initialize the evolution algorithm. ea.Initialize(fitnessEvaluator, genomeFactory, genomeList, DefaultPopulationSize, null, MaxEvaluations); // Finished. Return the evolution algorithm return ea; }
/// <summary> /// Creates the evolution algorithm container using the given factories and genome lists. /// </summary> /// <param name="genomeFactory1">The agent genome factory.</param> /// <param name="genomeFactory2">The maze genome factory.</param> /// <param name="genomeList1">The agent genome list.</param> /// <param name="genomeList2">The maze genome list.</param> /// <returns>The instantiated coevolution algorithm container.</returns> public override ICoevolutionAlgorithmContainer<NeatGenome, MazeGenome> CreateCoevolutionAlgorithmContainer( IGenomeFactory<NeatGenome> genomeFactory1, IGenomeFactory<MazeGenome> genomeFactory2, List<NeatGenome> genomeList1, List<MazeGenome> genomeList2) { List<NeatGenome> seedAgentPopulation = new List<NeatGenome>(); // Compute the maze max complexity ((MazeGenomeFactory) genomeFactory2).MaxComplexity = MazeUtils.DetermineMaxPartitions(_mazeHeight, _mazeWidth, 200); // Create maze decoder to decode initialization mazes MazeDecoder mazeDecoder = new MazeDecoder(_mazeHeight, _mazeWidth, _mazeScaleMultiplier); // Loop through every maze and evolve the requisite number of viable genomes that solve it for (int idx = 0; idx < genomeList2.Count; idx++) { Console.WriteLine(@"Evolving viable agents for maze population index {0} and maze ID {1}", idx, genomeList2[idx].Id); // Evolve the number of agents required to meet the success MC for the current maze List<NeatGenome> viableMazeAgents = EvolveViableAgents(genomeFactory1, genomeList1.ToList(), mazeDecoder.Decode(genomeList2[idx])); // Add the viable agent genomes who solve the current maze (but avoid adding duplicates, as identified by the genome ID) // Note that it's fine to have multiple mazes solved by the same agent, so in this case, we'll leave the agent // in the pool of seed agent genomes foreach ( NeatGenome viableMazeAgent in viableMazeAgents.Where( viableMazeAgent => seedAgentPopulation.Select(sap => sap.Id).Contains(viableMazeAgent.Id) == false)) { seedAgentPopulation.Add(viableMazeAgent); } } // If we still lack the genomes to fill out the agent seed genome count while still satisfying the maze MC, // iteratively pick a random maze and evolve agents on that maze until we reach the requisite number while (seedAgentPopulation.ToList().Count < AgentSeedGenomeCount) { FastRandom rndMazePicker = new FastRandom(); // Pick a random maze on which to evolve agent(s) MazeGenome mazeGenome = genomeList2[rndMazePicker.Next(genomeList2.Count - 1)]; Console.WriteLine( @"Continuing viable agent evolution on maze {0}, with {1} of {2} required agents in place", mazeGenome.Id, seedAgentPopulation.Count, AgentSeedGenomeCount); // Evolve the number of agents required to meet the success MC for the maze List<NeatGenome> viableMazeAgents = EvolveViableAgents(genomeFactory1, genomeList1.ToList(), mazeDecoder.Decode(mazeGenome)); // Iterate through each viable agent and remove them if they've already solved a maze or add them to the list // of viable agents if they have not foreach (NeatGenome viableMazeAgent in viableMazeAgents) { // If they agent has already solved maze and is in the list of viable agents, remove that agent // from the pool of seed genomes (this is done because here, we're interested in getting unique // agents and want to avoid an endless loop wherein the same viable agents are returned) if (seedAgentPopulation.Select(sap => sap.Id).Contains(viableMazeAgent.Id)) { genomeList1.Remove(viableMazeAgent); } // Otherwise, add that agent to the list of viable agents else { seedAgentPopulation.Add(viableMazeAgent); } } } // Set dummy fitness so that seed maze(s) will be marked as evaluated foreach (MazeGenome mazeGenome in genomeList2) { mazeGenome.EvaluationInfo.SetFitness(0); } // Create the NEAT (i.e. navigator) queueing evolution algorithm AbstractEvolutionAlgorithm<NeatGenome> neatEvolutionAlgorithm = new QueueingNeatEvolutionAlgorithm<NeatGenome>( new NeatEvolutionAlgorithmParameters { SpecieCount = AgentNumSpecies, MaxSpecieSize = AgentNumSpecies > 0 ? AgentDefaultPopulationSize/AgentNumSpecies : AgentDefaultPopulationSize }, new ParallelKMeansClusteringStrategy<NeatGenome>(new ManhattanDistanceMetric(1.0, 0.0, 10.0), ParallelOptions), null, NavigatorBatchSize, RunPhase.Primary, false, false, _navigatorEvolutionDataLogger, _navigatorLogFieldEnableMap, _navigatorPopulationGenomesDataLogger, _populationLoggingBatchInterval, _isNavigatorSpecieFixedSize); // Create the maze queueing evolution algorithm AbstractEvolutionAlgorithm<MazeGenome> mazeEvolutionAlgorithm = new QueueingNeatEvolutionAlgorithm<MazeGenome>( new NeatEvolutionAlgorithmParameters { SpecieCount = MazeNumSpecies, MaxSpecieSize = MazeNumSpecies > 0 ? MazeDefaultPopulationSize/MazeNumSpecies : MazeDefaultPopulationSize }, new ParallelKMeansClusteringStrategy<MazeGenome>(new ManhattanDistanceMetric(1.0, 0.0, 10.0), ParallelOptions), null, MazeBatchSize, RunPhase.Primary, false, false, _mazeEvolutionDataLogger, _mazeLogFieldEnableMap, _mazePopulationGenomesDataLogger, _populationLoggingBatchInterval, _isMazeSpecieFixedSize); // Create the maze phenome evaluator IPhenomeEvaluator<MazeStructure, BehaviorInfo> mazeEvaluator = new MazeEnvironmentMCSEvaluator( _maxTimesteps, _minSuccessDistance, BehaviorCharacterizationFactory, _numAgentSuccessCriteria, _numAgentFailedCriteria); // Create navigator phenome evaluator IPhenomeEvaluator<IBlackBox, BehaviorInfo> navigatorEvaluator = new MazeNavigatorMCSEvaluator( _maxTimesteps, _minSuccessDistance, BehaviorCharacterizationFactory, _numMazeSuccessCriteria); // Create maze genome decoder IGenomeDecoder<MazeGenome, MazeStructure> mazeGenomeDecoder = new MazeDecoder(_mazeHeight, _mazeWidth, _mazeScaleMultiplier); // Create navigator genome decoder IGenomeDecoder<NeatGenome, IBlackBox> navigatorGenomeDecoder = new NeatGenomeDecoder(ActivationScheme); // Create the maze genome evaluator IGenomeEvaluator<MazeGenome> mazeFitnessEvaluator = new ParallelGenomeBehaviorEvaluator<MazeGenome, MazeStructure>(mazeGenomeDecoder, mazeEvaluator, SelectionType.Queueing, SearchType.MinimalCriteriaSearch, ParallelOptions); // Create navigator genome evaluator IGenomeEvaluator<NeatGenome> navigatorFitnessEvaluator = new ParallelGenomeBehaviorEvaluator<NeatGenome, IBlackBox>(navigatorGenomeDecoder, navigatorEvaluator, SelectionType.Queueing, SearchType.MinimalCriteriaSearch, ParallelOptions); // Create the coevolution container ICoevolutionAlgorithmContainer<NeatGenome, MazeGenome> coevolutionAlgorithmContainer = new CoevolutionAlgorithmContainer<NeatGenome, MazeGenome>(neatEvolutionAlgorithm, mazeEvolutionAlgorithm); // Initialize the container and component algorithms coevolutionAlgorithmContainer.Initialize(navigatorFitnessEvaluator, genomeFactory1, seedAgentPopulation, AgentDefaultPopulationSize, mazeFitnessEvaluator, genomeFactory2, genomeList2, MazeDefaultPopulationSize, MaxGenerations, MaxEvaluations); return coevolutionAlgorithmContainer; }