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);
        }
示例#2
0
    /// <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);
        }
示例#5
0
    /// <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);
        }
示例#7
0
        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);
            }
        }
示例#8
0
        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);
        }
示例#9
0
        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);
        }
示例#11
0
    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.");
        }
    }
示例#12
0
        /// <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);
        }
示例#13
0
        /// <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);
        }
示例#14
0
        /// <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);
        }
示例#16
0
        //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);
        }
示例#18
0
        /// <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())
 {
 }
示例#20
0
    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();
    }
示例#21
0
        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);
        }
示例#23
0
        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);
    }
示例#25
0
        /// <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;
        }
示例#26
0
        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);
        }
示例#29
0
        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);
        }