private static NeatPopulation <double> CreateNeatPopulation( int count, double defaultFitness, IRandomSource rng) { MetaNeatGenome <double> metaNeatGenome = new MetaNeatGenome <double>( inputNodeCount: 3, outputNodeCount: 2, isAcyclic: true, activationFn: new NeuralNets.Double.ActivationFunctions.ReLU()); NeatPopulation <double> neatPop = NeatPopulationFactory <double> .CreatePopulation(metaNeatGenome, 1.0, count, rng); Assert.Equal(count, neatPop.GenomeList.Count); Assert.Equal(count, neatPop.GenomeIdSeq.Peek); // Assign the default fitness to all genomes. var genomeList = neatPop.GenomeList; for (int i = 0; i < count; i++) { var genome = genomeList[i]; genome.FitnessInfo = new FitnessInfo(defaultFitness); } // Init species. InitialiseSpecies(neatPop); return(neatPop); }
/// <summary> /// Create a new instance of <see cref="NeatEvolutionAlgorithm{T}"/> for the given neat experiment, and neat population. /// </summary> /// <param name="neatExperiment">A neat experiment instance; this conveys everything required to create a new evolution algorithm instance that is ready to be run.</param> /// <param name="neatPop">A pre constructed/loaded neat population; this must be compatible with the provided neat experiment, otherwise an exception will be thrown.</param> /// <returns>A new instance of <see cref="NeatEvolutionAlgorithm{T}"/>.</returns> public static NeatEvolutionAlgorithm <double> CreateNeatEvolutionAlgorithm( INeatExperiment <double> neatExperiment, NeatPopulation <double> neatPop) { // Validate MetaNeatGenome and NeatExperiment are compatible; normally the former should have been created based on the latter, but this is not enforced. MetaNeatGenome <double> metaNeatGenome = neatPop.MetaNeatGenome; ValidateCompatible(neatExperiment, metaNeatGenome); // Create a genomeList evaluator based on the experiment's configuration settings. var genomeListEvaluator = CreateGenomeListEvaluator(neatExperiment); // Create a speciation strategy based on the experiment's configuration settings. var speciationStrategy = CreateSpeciationStrategy(neatExperiment); // Create an instance of the default connection weight mutation scheme. var weightMutationScheme = WeightMutationSchemeFactory.CreateDefaultScheme(neatExperiment.ConnectionWeightScale); // Pull all of the parts together into an evolution algorithm instance. var ea = new NeatEvolutionAlgorithm <double>( neatExperiment.NeatEvolutionAlgorithmSettings, genomeListEvaluator, speciationStrategy, neatPop, neatExperiment.ComplexityRegulationStrategy, neatExperiment.ReproductionAsexualSettings, neatExperiment.ReproductionSexualSettings, weightMutationScheme); return(ea); }
public void VerifyPopulationStats() { IRandomSource rng = RandomDefaults.CreateRandomSource(0); // Create a test population. NeatPopulation <double> pop = CreateNeatPopulation(100, 10.0, rng); // Modify a few genome fitnesses. pop.GenomeList[10].FitnessInfo = new FitnessInfo(100.0); pop.GenomeList[20].FitnessInfo = new FitnessInfo(0.0); // Initialise the NEAT population species; the wider population stats are dependent on this occurring. InitialiseSpecies(pop); // Calc/update stats. pop.UpdateStats(PrimaryFitnessInfoComparer.Singleton, rng); // Validate stats. // Fitness stats. PopulationStatistics stats = pop.Stats; Assert.Equal(10, stats.BestGenomeIndex); Assert.Equal(100.0, stats.BestFitness.PrimaryFitness); Assert.Equal(10.8, stats.MeanFitness); Assert.Equal(1, stats.BestFitnessHistory.Length); Assert.Equal(100.0, stats.BestFitnessHistory.Total); // Complexity stats. Assert.Equal(6.0, stats.BestComplexity); Assert.Equal(6.0, stats.MeanComplexity); Assert.Equal(1, stats.MeanComplexityHistory.Length); Assert.Equal(6.0, stats.MeanComplexityHistory.Total); }
private static int CalcSpeciesTargetSizes( NeatPopulation <T> pop, double totalMeanFitness, IRandomSource rng) { // Handle specific case where all genomes/species have a zero fitness. // Assign all species an equal targetSize. if (0.0 == totalMeanFitness) { return(CalcSpeciesTargetSizes_ZeroTotalMeanFitness(pop, rng)); } // Calculate the new target size of each species using fitness sharing. double popSizeReal = pop.GenomeList.Count; Species <T>[] speciesArr = pop.SpeciesArray; int totalTargetSizeInt = 0; // The size of each specie is based on its fitness relative to the other species. for (int i = 0; i < speciesArr.Length; i++) { SpeciesStats stats = speciesArr[i].Stats; stats.TargetSizeReal = (stats.MeanFitness / totalMeanFitness) * popSizeReal; // Discretize targetSize (stochastic rounding). stats.TargetSizeInt = (int)NumericsUtils.ProbabilisticRound(stats.TargetSizeReal, rng); // Total up discretized target sizes. totalTargetSizeInt += stats.TargetSizeInt; } return(totalTargetSizeInt); }
/// <summary> /// Create a new instance of <see cref="NeatEvolutionAlgorithm{T}"/> for the given neat experiment. /// </summary> /// <param name="neatExperiment">A neat experiment instance; this conveys everything required to create a new evolution algorithm instance that is ready to be run.</param> /// <returns>A new instance of <see cref="NeatEvolutionAlgorithm{T}"/>.</returns> public static NeatEvolutionAlgorithm <double> CreateNeatEvolutionAlgorithm( INeatExperiment <double> neatExperiment) { // Create a genomeList evaluator based on the experiment's configuration settings. var genomeListEvaluator = CreateGenomeListEvaluator(neatExperiment); // Create a MetaNeatGenome. var metaNeatGenome = CreateMetaNeatGenome(neatExperiment); // Create an initial population of genomes. NeatPopulation <double> neatPop = NeatPopulationFactory <double> .CreatePopulation( metaNeatGenome, connectionsProportion : neatExperiment.InitialInterconnectionsProportion, popSize : neatExperiment.PopulationSize); // Create a speciation strategy based on the experiment's configuration settings. var speciationStrategy = CreateSpeciationStrategy(neatExperiment); // Create an instance of the default connection weight mutation scheme. var weightMutationScheme = WeightMutationSchemeFactory.CreateDefaultScheme(neatExperiment.ConnectionWeightScale); // Pull all of the parts together into an evolution algorithm instance. var ea = new NeatEvolutionAlgorithm <double>( neatExperiment.NeatEvolutionAlgorithmSettings, genomeListEvaluator, speciationStrategy, neatPop, neatExperiment.ComplexityRegulationStrategy, neatExperiment.ReproductionAsexualSettings, neatExperiment.ReproductionSexualSettings, weightMutationScheme); return(ea); }
/// <summary> /// Handle specific case where all genomes/species have a zero fitness. /// </summary> private static int CalcSpeciesTargetSizes_ZeroTotalMeanFitness(NeatPopulation <T> pop, IRandomSource rng) { // Assign all species an equal targetSize. Species <T>[] speciesArr = pop.SpeciesArray; double popSizeReal = pop.GenomeList.Count; double targetSizeReal = popSizeReal / speciesArr.Length; // Keep a total of all allocated target sizes, typically this will vary slightly from the // required target population size due to rounding of each real valued target size. int totalTargetSizeInt = 0; for (int i = 0; i < speciesArr.Length; i++) { SpeciesStats stats = speciesArr[i].Stats; stats.TargetSizeReal = targetSizeReal; // Stochastic rounding will result in equal allocation if targetSizeReal is a whole // number, otherwise it will help to distribute allocations fairly. stats.TargetSizeInt = (int)NumericsUtils.ProbabilisticRound(targetSizeReal, rng); // Total up discretized target sizes. totalTargetSizeInt += stats.TargetSizeInt; } return(totalTargetSizeInt); }
public void CreatePopulation() { MetaNeatGenome <double> metaNeatGenome = new( inputNodeCount : 3, outputNodeCount : 2, isAcyclic : true, activationFn : new NeuralNets.Double.ActivationFunctions.ReLU()); int count = 10; NeatPopulation <double> neatPop = NeatPopulationFactory <double> .CreatePopulation(metaNeatGenome, 1.0, count, RandomDefaults.CreateRandomSource()); Assert.Equal(count, neatPop.GenomeList.Count); Assert.Equal(count, neatPop.GenomeIdSeq.Peek); // The population factory assigns the same innovation IDs to matching structures in the genomes it creates. // In this test there are 5 nodes and 6 connections in each genome, and they are each identifiably // the same structure in each of the genomes (e.g. input 0 or whatever) and so have the same innovation ID // across all of the genomes. // Thus in total although we created N genomes there are only 5 innovation IDs allocated (5 nodes). Assert.Equal(5, neatPop.InnovationIdSeq.Peek); // Loop the created genomes. for (int i = 0; i < count; i++) { var genome = neatPop.GenomeList[i]; Assert.Equal(i, genome.Id); Assert.Equal(0, genome.BirthGeneration); TestGenome(genome); } }
public void SaveAndLoadPopulationToZipArchive() { // Create a test population. NeatPopulation <double> pop = NestGenomeTestUtils.CreateNeatPopulation(); // Build path to test population folder. string parentPath = Path.Combine(Directory.GetCurrentDirectory(), "test-pops"); // Delete folder if it already exists. if (Directory.Exists(parentPath)) { Directory.Delete(parentPath, true); } // Create an empty parent folder to save populations into. Directory.CreateDirectory(parentPath); // Save the population to the unit test output folder. NeatPopulationSaver <double> .SaveToZipArchive(pop.GenomeList, parentPath, "pop2", System.IO.Compression.CompressionLevel.Optimal); // Load the population. NeatPopulationLoader <double> loader = NeatPopulationLoaderFactory.CreateLoaderDouble(pop.MetaNeatGenome); string populationZipPath = Path.Combine(parentPath, "pop2.zip"); List <NeatGenome <double> > genomeListLoaded = loader.LoadFromZipArchive(populationZipPath); // Compare the loaded genomes with the original genome list. IOTestUtils.CompareGenomeLists(pop.GenomeList, genomeListLoaded); }
private static void CalcAndStoreSpeciesTargetSizes( NeatPopulation <T> pop, IRandomSource rng) { double totalMeanFitness = pop.TotalSpeciesMeanFitness; int totalTargetSizeInt = 0; // Handle specific case where all genomes/species have a zero fitness. // Assign all species an equal targetSize. if (0.0 == totalMeanFitness) { totalTargetSizeInt = CalcSpeciesTargetSizesInner_ZeroTotalMeanFitness(pop, rng); } else { // Calculate the new target size of each species using fitness sharing. double popSizeReal = pop.GenomeList.Count; Species <T>[] speciesArr = pop.SpeciesArray; // The size of each specie is based on its fitness relative to the other species. for (int i = 0; i < speciesArr.Length; i++) { SpeciesStats stats = speciesArr[i].Stats; stats.TargetSizeReal = (stats.MeanFitness / totalMeanFitness) * popSizeReal; // Discretize targetSize (stochastic rounding). stats.TargetSizeInt = (int)NumericsUtils.ProbabilisticRound(stats.TargetSizeReal, rng); // Total up discretized target sizes. totalTargetSizeInt += stats.TargetSizeInt; } } // Adjust each species' target allocation such that the sum total matches the required population size. AdjustSpeciesTargetSizes(pop, totalTargetSizeInt, rng); }
private static void AdjustSpeciesTargetSizes( NeatPopulation <T> pop, int totalTargetSizeInt, IRandomSource rng) { // Discretized target sizes may total up to a value that is not equal to the required population size. // Here we check this and if the total does not match the required population size then we adjust the // species' targetSizeInt values to compensate for the difference. int popSize = pop.GenomeList.Count; int targetSizeDeltaInt = totalTargetSizeInt - popSize; if (targetSizeDeltaInt < 0) { // Target size is too low; adjust up. AdjustSpeciesTargetSizesUp(pop.SpeciesArray, targetSizeDeltaInt, rng); } else if (targetSizeDeltaInt > 0) { // Target size is too high; adjust down. AdjustSpeciesTargetSizesDown(pop.SpeciesArray, targetSizeDeltaInt, rng); } // Assert that Sum(TargetSizeInt) == popSize. Debug.Assert(pop.SpeciesArray.Sum(x => x.Stats.TargetSizeInt) == popSize); }
private static void AdjustSpeciesTargetSizes_AccommodateBestGenomeSpecies( NeatPopulation <T> pop, IRandomSource rng) { // Test if the best genome is in a species with a zero target size allocation. int bestGenomeSpeciesIdx = pop.NeatPopulationStats.BestGenomeSpeciesIdx; Species <T>[] speciesArr = pop.SpeciesArray !; if (speciesArr[bestGenomeSpeciesIdx].Stats.TargetSizeInt > 0) { // Nothing to do. The best genome is in a species with a non-zero allocation. return; } // Set the target size of the best genome species to a allow the best genome to survive to the next generation. speciesArr[bestGenomeSpeciesIdx].Stats.TargetSizeInt++; // Adjust down the target size of one of the other species to compensate. // Pick a species at random (but not the champ species). Note that this may result in a species with a zero // target size, this is OK at this stage. We handle allocations of zero elsewhere. // Create an array of shuffled indexes to select from, i.e. all of the species except for the one with the best genome in it. int speciesCount = speciesArr.Length; int[] speciesIdxArr = new int[speciesCount - 1]; for (int i = 0; i < bestGenomeSpeciesIdx; i++) { speciesIdxArr[i] = i; } for (int i = bestGenomeSpeciesIdx + 1; i < speciesCount; i++) { speciesIdxArr[i - 1] = i; } SpanUtils.Shuffle(speciesIdxArr.AsSpan(), rng); // Loop the species indexes. bool success = false; foreach (int speciesIdx in speciesIdxArr) { if (speciesArr[speciesIdx].Stats.TargetSizeInt > 0) { speciesArr[speciesIdx].Stats.TargetSizeInt--; success = true; break; } } if (!success) { throw new Exception("All species have a zero target size."); } }
/// <summary> /// Construct a new instance. /// </summary> /// <param name="eaSettings">NEAT evolution algorithm settings.</param> /// <param name="evaluator">An evaluator of lists of genomes.</param> /// <param name="speciationStrategy">Speciation strategy.</param> /// <param name="population">An initial population of genomes.</param> /// <param name="complexityRegulationStrategy">Complexity regulation strategy.</param> /// <param name="reproductionAsexualSettings">Asexual reproduction settings.</param> /// <param name="reproductionSexualSettings">Sexual reproduction settings.</param> /// <param name="weightMutationScheme">Connection weight mutation scheme.</param> /// <param name="rng">Random source.</param> public NeatEvolutionAlgorithm( NeatEvolutionAlgorithmSettings eaSettings, IGenomeListEvaluator <NeatGenome <T> > evaluator, ISpeciationStrategy <NeatGenome <T>, T> speciationStrategy, NeatPopulation <T> population, IComplexityRegulationStrategy complexityRegulationStrategy, NeatReproductionAsexualSettings reproductionAsexualSettings, NeatReproductionSexualSettings reproductionSexualSettings, WeightMutationScheme <T> weightMutationScheme, IRandomSource rng) { _eaSettingsCurrent = eaSettings ?? throw new ArgumentNullException(nameof(eaSettings)); _eaSettingsComplexifying = eaSettings; _eaSettingsSimplifying = eaSettings.CreateSimplifyingSettings(); _evaluator = evaluator ?? throw new ArgumentNullException(nameof(evaluator)); _speciationStrategy = speciationStrategy ?? throw new ArgumentNullException(nameof(speciationStrategy)); _pop = population ?? throw new ArgumentNullException(nameof(population)); _complexityRegulationStrategy = complexityRegulationStrategy ?? throw new ArgumentNullException(nameof(complexityRegulationStrategy)); if (reproductionAsexualSettings == null) { throw new ArgumentNullException(nameof(reproductionAsexualSettings)); } if (reproductionSexualSettings == null) { throw new ArgumentNullException(nameof(reproductionSexualSettings)); } _rng = rng; _genomeComparerDescending = new GenomeComparerDescending(evaluator.FitnessComparer); if (eaSettings.SpeciesCount > population.PopulationSize) { throw new ArgumentException("Species count is higher then the population size."); } _generationSeq = new Int32Sequence(); _reproductionAsexual = new NeatReproductionAsexual <T>( _pop.MetaNeatGenome, _pop.GenomeBuilder, _pop.GenomeIdSeq, population.InnovationIdSeq, _generationSeq, _pop.AddedNodeBuffer, reproductionAsexualSettings, weightMutationScheme); _reproductionSexual = new NeatReproductionSexual <T>( _pop.MetaNeatGenome, _pop.GenomeBuilder, _pop.GenomeIdSeq, _generationSeq, reproductionSexualSettings); _offspringBuilder = new OffspringBuilder <T>( _reproductionAsexual, _reproductionSexual, eaSettings.InterspeciesMatingProportion, evaluator.FitnessComparer); }
/// <summary> /// Calc and store species target sizes based on relative mean fitness of each species, i.e. as per NEAT fitness sharing method. /// Then calc and store the elite, selection and offspring allocations/counts, per species. /// </summary> public static void CalcAndStoreSpeciesAllocationSizes( NeatPopulation <T> pop, NeatEvolutionAlgorithmSettings eaSettings, IRandomSource rng) { // Calculate the new target size of each species using fitness sharing. CalcAndStoreSpeciesTargetSizes(pop, rng); // Calculate elite, selection and offspring counts, per species. CalculateAndStoreEliteSelectionOffspringCounts(pop, eaSettings, rng); }
/// <summary> /// Calculate and update a number of statistical values and target size values on each species in the givben population. /// </summary> /// <param name="pop">The population to update species statistics on.</param> /// <param name="eaSettings">Evolution algorithm settings.</param> /// <param name="rng">Random source.</param> public static void CalcAndStoreSpeciesStats( NeatPopulation <T> pop, NeatEvolutionAlgorithmSettings eaSettings, IRandomSource rng) { // Calc and store the mean fitness of each species. CalcAndStoreSpeciesFitnessMeans(pop); // Calc and store the target size of each species (based on the NEAT fitness sharing method). SpeciesAllocationCalcs <T> .CalcAndStoreSpeciesAllocationSizes(pop, eaSettings, rng); }
/// <summary> /// Calc species target sizes based on relative mean fitness of each species, i.e. as per NEAT fitness sharing method. /// </summary> public static void CalcSpeciesTargetSizes(NeatPopulation <T> pop, IRandomSource rng) { // Calc mean fitness of all species, and get sum of all species means. double totalMeanFitness = UpdateSpeciesFitnessMeans(pop.SpeciesArray); // Calculate the new target size of each species using fitness sharing. int totalTargetSizeInt = CalcSpeciesTargetSizes(pop, totalMeanFitness, rng); // Adjust each species' target allocation such that the sum total matches the required population size. AdjustSpeciesTargetSizes(pop, totalTargetSizeInt, rng); }
//private IGenomeCollectionEvaluator<NeatGenome<double>> CreateGenomeListEvaluator() //{ // var genomeDecoder = new NeatGenomeAcyclicDecoder(false); // var phenomeEvaluator = new BinaryElevenMultiplexerEvaluator(); // var genomeCollectionEvaluator = new SerialGenomeListEvaluator<NeatGenome<double>, IPhenome<double>>(genomeDecoder, phenomeEvaluator); // return genomeListEvaluator; //} private static NeatPopulation <double> CreatePopulation( MetaNeatGenome <double> metaNeatGenome, int popSize) { NeatPopulation <double> pop = NeatPopulationFactory <double> .CreatePopulation( metaNeatGenome, connectionsProportion : 1.0, popSize : popSize, rng : RandomDefaults.CreateRandomSource()); return(pop); }
private static void InitialiseSpecies(NeatPopulation <double> neatPop) { // Create a speciation strategy instance. var distanceMetric = new ManhattanDistanceMetric(1.0, 0.0, 10.0); var speciationStrategy = new Speciation.GeneticKMeans.Parallelized.GeneticKMeansSpeciationStrategy <double>(distanceMetric, 5, 4); // Apply the speciation strategy. var genomeComparerDescending = new GenomeComparerDescending(PrimaryFitnessInfoComparer.Singleton); IRandomSource rng = RandomDefaults.CreateRandomSource(0); neatPop.InitialiseSpecies(speciationStrategy, 3, genomeComparerDescending, rng); }
/// <summary> /// For each species, allocate the EliteSizeInt, OffspringCount (broken down into OffspringAsexualCount and OffspringSexualCount), /// and SelectionSizeInt values. /// </summary> /// <param name="pop"></param> /// <param name="eaSettings"></param> /// <param name="rng"></param> private static void CalculateAndStoreEliteSelectionOffspringCounts( NeatPopulation <T> pop, NeatEvolutionAlgorithmSettings eaSettings, IRandomSource rng) { Species <T>[] speciesArr = pop.SpeciesArray; // Loop the species, calculating and storing the various size/count properties. for (int i = 0; i < speciesArr.Length; i++) { bool isBestGenomeSpecies = (pop.BestGenomeSpeciesIdx == i); AllocateEliteSelectionOffspringCounts(speciesArr[i], eaSettings, isBestGenomeSpecies, rng); } }
/// <summary> /// Construct a new instance. /// </summary> /// <param name="eaSettings">NEAT evolution algorithm settings.</param> /// <param name="evaluator">An evaluator of lists of genomes.</param> /// <param name="speciationStrategy">Speciation strategy.</param> /// <param name="population">An initial population of genomes.</param> /// <param name="reproductionAsexualSettings">Asexual reproduction settings.</param> /// <param name="reproductionSexualSettings">Sexual reproduction settings.</param> /// <param name="weightMutationScheme">Connection weight mutation scheme.</param> public NeatEvolutionAlgorithm( NeatEvolutionAlgorithmSettings eaSettings, IGenomeListEvaluator <NeatGenome <T> > evaluator, ISpeciationStrategy <NeatGenome <T>, T> speciationStrategy, NeatPopulation <T> population, NeatReproductionAsexualSettings reproductionAsexualSettings, NeatReproductionSexualSettings reproductionSexualSettings, WeightMutationScheme <T> weightMutationScheme) : this(eaSettings, evaluator, speciationStrategy, population, reproductionAsexualSettings, reproductionSexualSettings, weightMutationScheme, RandomDefaults.CreateRandomSource()) { }
private void btnCreateRandomPop_Click(object sender, EventArgs e) { INeatExperiment <double> neatExperiment = GetNeatExperiment(); MetaNeatGenome <double> metaNeatGenome = NeatUtils.CreateMetaNeatGenome(neatExperiment); // Create an initial population of genomes. _neatPop = NeatPopulationFactory <double> .CreatePopulation( metaNeatGenome, connectionsProportion : neatExperiment.InitialInterconnectionsProportion, popSize : neatExperiment.PopulationSize); // Update UI. UpdateUIState(); }
public void CreateGenome() { var metaNeatGenome = new MetaNeatGenome <double>( inputNodeCount: 10, outputNodeCount: 20, isAcyclic: true, activationFn: new NeuralNets.Double.ActivationFunctions.ReLU()); var genomeBuilder = NeatGenomeBuilderFactory <double> .Create(metaNeatGenome); int count = 100; NeatPopulation <double> pop = NeatPopulationFactory <double> .CreatePopulation(metaNeatGenome, 0.1, count, RandomDefaults.CreateRandomSource()); var generationSeq = new Int32Sequence(); var strategy = new UniformCrossoverReproductionStrategy <double>( pop.MetaNeatGenome.IsAcyclic, 0.02, genomeBuilder, pop.GenomeIdSeq, generationSeq); IRandomSource rng = RandomDefaults.CreateRandomSource(0); var cyclicGraphCheck = new CyclicGraphCheck(); for (int i = 0; i < 1000; i++) { // Randomly select two parents from the population. var genome1 = pop.GenomeList[rng.Next(count)]; var genome2 = pop.GenomeList[rng.Next(count)]; var childGenome = strategy.CreateGenome(genome1, genome2, rng); // The connection genes should be sorted. Assert.True(SortUtils.IsSortedAscending <DirectedConnection>(childGenome.ConnectionGenes._connArr)); // The child genome should describe an acyclic graph, i.e. the new connection should not have // formed a cycle in the graph. var digraph = childGenome.DirectedGraph; Assert.False(cyclicGraphCheck.IsCyclic(digraph)); // The child genome node IDs should be a superset of those from parent1 + parent2. var childNodeIdSet = GetNodeIdSet(childGenome); var parentIdSet = GetNodeIdSet(genome1); parentIdSet.IntersectWith(GetNodeIdSet(genome2)); Assert.True(childNodeIdSet.IsSupersetOf(parentIdSet)); } }
public void VerifyNeatPopulationStats() { IRandomSource rng = RandomDefaults.CreateRandomSource(0); // Create test population and apply speciation strategy. NeatPopulation <double> neatPop = CreateNeatPopulation(30, 10.0, rng); // Loop the species; assign the same fitness to genomes within each species. for (int i = 0; i < neatPop.SpeciesArray.Length; i++) { double fitness = (i + 1) * 10.0; neatPop.SpeciesArray[i].GenomeList.ForEach(x => x.FitnessInfo = new FitnessInfo(fitness)); } // Calc NeatPopulation statistics. neatPop.UpdateStats(PrimaryFitnessInfoComparer.Singleton, rng); // Validate expected mean fitness for each species. for (int i = 0; i < neatPop.SpeciesArray.Length; i++) { double expectedMeanFitness = (i + 1) * 10.0; Assert.Equal(expectedMeanFitness, neatPop.SpeciesArray[i].Stats.MeanFitness); } // Validate SumSpeciesMeanFitness. double expectedSumSpeciesMeanFitness = 10.0 + 20.0 + 30.0; Assert.Equal(expectedSumSpeciesMeanFitness, neatPop.NeatPopulationStats.SumSpeciesMeanFitness); // Validate BestGenomeSpeciesIdx. Assert.Equal(2, neatPop.NeatPopulationStats.BestGenomeSpeciesIdx); // Assign a high fitness to one of the genomes, and check that BestGenomeSpeciesIdx is updated accordingly. neatPop.SpeciesArray[0].GenomeList[2].FitnessInfo = new FitnessInfo(100.0); // Note. The species must be re-initialised in order for the fit genome to be sorted correctly within its // containing species. InitialiseSpecies(neatPop); neatPop.UpdateStats(PrimaryFitnessInfoComparer.Singleton, rng); Assert.Equal(0, neatPop.NeatPopulationStats.BestGenomeSpeciesIdx); // Perform the same test again with the best genome in the second species. neatPop.SpeciesArray[1].GenomeList[3].FitnessInfo = new FitnessInfo(200.0); InitialiseSpecies(neatPop); neatPop.UpdateStats(PrimaryFitnessInfoComparer.Singleton, rng); Assert.Equal(1, neatPop.NeatPopulationStats.BestGenomeSpeciesIdx); }
private static NeatPopulation <double> CreateNeatPopulation( int count, int inputNodeCount, int outputNodeCount, double connectionsProportion) { MetaNeatGenome <double> metaNeatGenome = new MetaNeatGenome <double>( inputNodeCount: inputNodeCount, outputNodeCount: outputNodeCount, isAcyclic: true, activationFn: new SharpNeat.NeuralNet.Double.ActivationFunctions.ReLU()); NeatPopulation <double> neatPop = NeatPopulationFactory <double> .CreatePopulation(metaNeatGenome, 1.0, count, RandomDefaults.CreateRandomSource()); return(neatPop); }
public void UpdateSpeciesAllocationSizes() { IRandomSource rng = RandomDefaults.CreateRandomSource(0); NeatEvolutionAlgorithmSettings eaSettings = new() { SpeciesCount = 4 }; // Create population. NeatPopulation <double> neatPop = CreateNeatPopulation(100, eaSettings.SpeciesCount, 2, 2, 1.0); // Manually set-up some species. var speciesArr = neatPop.SpeciesArray; speciesArr[0].GenomeList.AddRange(neatPop.GenomeList.Take(25)); speciesArr[1].GenomeList.AddRange(neatPop.GenomeList.Skip(25).Take(25)); speciesArr[2].GenomeList.AddRange(neatPop.GenomeList.Skip(50).Take(25)); speciesArr[3].GenomeList.AddRange(neatPop.GenomeList.Skip(75).Take(25)); // Manually assign fitness scores to the genomes. speciesArr[0].GenomeList.ForEach(x => x.FitnessInfo = new FitnessInfo(100.0)); speciesArr[1].GenomeList.ForEach(x => x.FitnessInfo = new FitnessInfo(200.0)); speciesArr[2].GenomeList.ForEach(x => x.FitnessInfo = new FitnessInfo(400.0)); speciesArr[3].GenomeList.ForEach(x => x.FitnessInfo = new FitnessInfo(800.0)); // Invoke species target size calcs. neatPop.UpdateStats(PrimaryFitnessInfoComparer.Singleton, rng); SpeciesAllocationCalcs <double> .UpdateSpeciesAllocationSizes( neatPop, eaSettings, RandomDefaults.CreateRandomSource()); // Species target sizes should be relative to the species mean fitness. double totalMeanFitness = 1500.0; double popSize = 100.0; Assert.Equal((100.0 / totalMeanFitness) * popSize, speciesArr[0].Stats.TargetSizeReal); Assert.Equal((200.0 / totalMeanFitness) * popSize, speciesArr[1].Stats.TargetSizeReal); Assert.Equal((400.0 / totalMeanFitness) * popSize, speciesArr[2].Stats.TargetSizeReal); Assert.Equal((800.0 / totalMeanFitness) * popSize, speciesArr[3].Stats.TargetSizeReal); // Note. Discretized target sizes will generally be equal to ceil(TargetSizeReal) or floor(TargetSizeReal), // but may not be due to the target size adjustment logic that is used to ensure that sum(TargetSizeInt) is equal // to the required population size. // Check that sum(TargetSizeInt) is equal to the required population size. Assert.Equal(speciesArr.Sum(x => x.Stats.TargetSizeInt), neatPop.GenomeList.Count); }
/// <summary> /// Calc mean fitness of all species, and store the results on each species' stats object. /// </summary> /// <param name="pop">The population.</param> /// <returns>Sum of species mean fitnesses.</returns> private static void CalcAndStoreSpeciesFitnessMeans(NeatPopulation <T> pop) { Species <T>[] speciesArr = pop.SpeciesArray; // Calc mean fitness of all species, and sum of all species means. double totalMeanFitness = 0.0; for (int i = 0; i < speciesArr.Length; i++) { var species = speciesArr[i]; double meanFitness = species.GenomeList.Average(x => x.FitnessInfo.PrimaryFitness); species.Stats.MeanFitness = meanFitness; totalMeanFitness += meanFitness; } pop.TotalSpeciesMeanFitness = totalMeanFitness; }
public static void TestSpeciateAdd( int popSize, int inputNodeCount, int outputNodeCount, double connectionsProportion, IDistanceMetric <double> distanceMetric, ISpeciationStrategy <NeatGenome <double>, double> speciationStrategy, IRandomSource rng, bool validateNearestSpecies = true) { // Create population. NeatPopulation <double> neatPop = CreateNeatPopulation(popSize, inputNodeCount, outputNodeCount, connectionsProportion); // Split the population into three. int popSize1 = popSize / 3; int popSize2 = popSize / 3; int popSize3 = popSize - (popSize1 + popSize2); var genomeList1 = neatPop.GenomeList.GetRange(0, popSize1); var genomeList2 = neatPop.GenomeList.GetRange(popSize1, popSize2); var genomeList3 = neatPop.GenomeList.GetRange(popSize1 + popSize2, popSize3); for (int i = 0; i < 6; i++) { int speciesCount = rng.Next(1, (neatPop.GenomeList.Count / 4) + 1); var fullGenomeList = new List <NeatGenome <double> >(genomeList1); // Invoke speciation strategy, and run tests var speciesArr = speciationStrategy.SpeciateAll(genomeList1, speciesCount, rng); ValidationTests(speciesArr, distanceMetric, speciesCount, fullGenomeList, validateNearestSpecies); // Add second batch of genomes, and re-run tests. speciationStrategy.SpeciateAdd(genomeList2, speciesArr, rng); fullGenomeList.AddRange(genomeList2); ValidationTests(speciesArr, distanceMetric, speciesCount, fullGenomeList, validateNearestSpecies); // Add third batch of genomes, and re-run tests. speciationStrategy.SpeciateAdd(genomeList3, speciesArr, rng); fullGenomeList.AddRange(genomeList3); ValidationTests(speciesArr, distanceMetric, speciesCount, fullGenomeList, validateNearestSpecies); } }
/// <summary> /// Create a new instance of <see cref="NeatEvolutionAlgorithm{T}"/> for the given neat experiment. /// </summary> /// <param name="neatExperiment">A neat experiment; conveys everything required to create a new evolution algorithm instance that is ready to be run.</param> /// <returns>A new instance of <see cref="NeatEvolutionAlgorithm{T}"/>.</returns> public static NeatEvolutionAlgorithm <double> CreateNeatEvolutionAlgorithm( INeatExperiment <double> neatExperiment) { // Create a genomeList evaluator based on the experiment's configuration settings. var genomeListEvaluator = CreateGenomeListEvaluator(neatExperiment); // Resolve the configured activation function name to an activation function instance. var actFnFactory = new DefaultActivationFunctionFactory <double>(neatExperiment.EnableHardwareAcceleratedActivationFunctions); var activationFn = actFnFactory.GetActivationFunction(neatExperiment.ActivationFnName); // Construct a MetaNeatGenome. var metaNeatGenome = new MetaNeatGenome <double>( inputNodeCount: neatExperiment.EvaluationScheme.InputCount, outputNodeCount: neatExperiment.EvaluationScheme.OutputCount, isAcyclic: neatExperiment.IsAcyclic, activationFn: activationFn); // Create an initial population of genomes. NeatPopulation <double> neatPop = NeatPopulationFactory <double> .CreatePopulation( metaNeatGenome, connectionsProportion : neatExperiment.InitialInterconnectionsProportion, popSize : neatExperiment.PopulationSize, rng : RandomDefaults.CreateRandomSource()); // Create a speciation strategy based on the experiment's configuration settings. var speciationStrategy = CreateSpeciationStrategy(neatExperiment); // Create an instance of the default connection weight mutation scheme. var weightMutationScheme = WeightMutationSchemeFactory.CreateDefaultScheme(neatExperiment.ConnectionWeightScale); // Pull all of the parts together into an evolution algorithm instance. var ea = new NeatEvolutionAlgorithm <double>( neatExperiment.NeatEvolutionAlgorithmSettings, genomeListEvaluator, speciationStrategy, neatPop, neatExperiment.ComplexityRegulationStrategy, neatExperiment.ReproductionAsexualSettings, neatExperiment.ReproductionSexualSettings, weightMutationScheme); return(ea); }
private static Species <double> CreateTestSpecies(int genomeCount) { // Create the species genomes; we use NeatPopulationFactory for this. MetaNeatGenome <double> metaNeatGenome = new MetaNeatGenome <double>( inputNodeCount: 1, outputNodeCount: 1, isAcyclic: true, activationFn: new SharpNeat.NeuralNets.Double.ActivationFunctions.ReLU()); NeatPopulation <double> neatPop = NeatPopulationFactory <double> .CreatePopulation(metaNeatGenome, 1.0, genomeCount, RandomDefaults.CreateRandomSource()); // Create the species object, and assign all of the created genomes to it. var species = new Species <double>(0, new ConnectionGenes <double>(0)); species.GenomeList.AddRange(neatPop.GenomeList); // Return the species. return(species); }
public void TestInitialConnections() { MetaNeatGenome<double> metaNeatGenome = new MetaNeatGenome<double>( inputNodeCount: 100, outputNodeCount: 200, isAcyclic: true, activationFn: new SharpNeat.NeuralNet.Double.ActivationFunctions.ReLU()); NeatPopulation<double> neatPop = NeatPopulationFactory<double>.CreatePopulation(metaNeatGenome, 0.5, 1, RandomDefaults.CreateRandomSource()); NeatGenome<double> genome = neatPop.GenomeList[0]; Assert.AreEqual(10000, genome.ConnectionGenes.Length); Assert.IsTrue(SortUtils.IsSortedAscending(genome.ConnectionGenes._connArr)); CalcWeightMinMaxMean(genome.ConnectionGenes._weightArr, out double min, out double max, out double mean); Assert.IsTrue(min < -genome.MetaNeatGenome.ConnectionWeightRange * 0.98); Assert.IsTrue(max > genome.MetaNeatGenome.ConnectionWeightRange * 0.98); Assert.IsTrue(Math.Abs(mean) < 0.1); }
public void SaveAndLoadPopulationToZipArchive() { // Create a test population. NeatPopulation <double> pop = NestGenomeTestUtils.CreateNeatPopulation(); // Create a parent folder to save populations into. string parentPath = Path.Combine(TestContext.TestRunDirectory, "test-pops"); Directory.CreateDirectory(parentPath); // Save the population to the unit test output folder. NeatPopulationSaver <double> .SaveToZipArchive(pop.GenomeList, parentPath, "pop2", System.IO.Compression.CompressionLevel.Optimal); // Load the population. NeatPopulationLoader <double> loader = NeatPopulationLoaderFactory.CreateLoaderDouble(pop.MetaNeatGenome); string populationZipPath = Path.Combine(parentPath, "pop2.zip"); List <NeatGenome <double> > genomeListLoaded = loader.LoadFromZipArchive(populationZipPath); // Compare the loaded genomes with the original genome list. IOTestUtils.CompareGenomeLists(pop.GenomeList, genomeListLoaded); }