/// <summary>
        /// Handle specific case where all genomes/species have a zero fitness.
        /// </summary>
        private static int CalcSpeciesTargetSizesInner_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.StochasticRound(targetSizeReal, rng);

                // Total up discretized target sizes.
                totalTargetSizeInt += stats.TargetSizeInt;
            }

            return(totalTargetSizeInt);
        }
        private static void UpdateSpeciesTargetSizes(
            NeatPopulation <T> pop, IRandomSource rng)
        {
            double totalMeanFitness   = pop.NeatPopulationStats.SumSpeciesMeanFitness;
            int    totalTargetSizeInt = 0;

            // Handle specific case where all genomes/species have a zero fitness.
            // Assign all species an equal targetSize.
            if (totalMeanFitness == 0.0)
            {
                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.StochasticRound(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 AllocateEliteSelectionOffspringCounts(
            Species <T> species,
            NeatEvolutionAlgorithmSettings eaSettings,
            bool isBestGenomeSpecies,
            IRandomSource rng)
        {
            SpeciesStats stats = species.Stats;

            // Special case - zero target size.
            if (stats.TargetSizeInt == 0)
            {
                Debug.Assert(!isBestGenomeSpecies, "Zero target size assigned to specie that contains the best genome.");
                stats.EliteSizeInt          = 0;
                stats.OffspringCount        = 0;
                stats.OffspringAsexualCount = 0;
                stats.OffspringSexualCount  = 0;
                stats.SelectionSizeInt      = 0;
                return;
            }

            // Calculate the elite size as a proportion of the current species size.
            // Note. We discretize the real size with a probabilistic handling of the fractional part.
            double eliteSizeReal = species.GenomeList.Count * eaSettings.ElitismProportion;
            int    eliteSizeInt  = (int)NumericsUtils.StochasticRound(eliteSizeReal, rng);

            // Ensure eliteSizeInt is no larger than the current target size. (I.e. the value was
            // calculated as a proportion of the current size, not the new target size).
            stats.EliteSizeInt = Math.Min(eliteSizeInt, stats.TargetSizeInt);

            // Special case: ensure the species with the best genome preserves that genome.
            // Note. This is done even for a target size of one, which would mean that no offspring are
            // produced from the best genome, apart from the (usually small) chance of a cross-species mating.
            if (isBestGenomeSpecies && stats.EliteSizeInt == 0)
            {
                stats.EliteSizeInt = 1;
            }

            // Determine how many offspring to produce for the species.
            stats.OffspringCount = stats.TargetSizeInt - stats.EliteSizeInt;

            // Determine the split between asexual and sexual reproduction. Again using probabilistic
            // rounding to compensate for any rounding bias.
            double offspringAsexualCountReal = stats.OffspringCount * eaSettings.OffspringAsexualProportion;

            stats.OffspringAsexualCount = (int)NumericsUtils.StochasticRound(offspringAsexualCountReal, rng);
            stats.OffspringSexualCount  = stats.OffspringCount - stats.OffspringAsexualCount;

            // Calculate the selectionSize. The number of the species' fittest genomes that are selected from
            // to create offspring.
            // We ensure this is at least one; if TargetSizeInt is zero then it doesn't matter because no genomes will be
            // selected from this species to produce offspring, except for cross-species mating, hence the minimum of one is
            // a useful general approach.
            double selectionSizeReal = species.GenomeList.Count * eaSettings.SelectionProportion;

            stats.SelectionSizeInt = Math.Max(1, (int)NumericsUtils.StochasticRound(selectionSizeReal, rng));
        }
Пример #4
0
        public void StochasticRound()
        {
            IRandomSource rng = RandomDefaults.CreateRandomSource(0);

            for (int i = 0; i < 1_000_000; i++)
            {
                double valReal  = 100 * rng.NextDouble();
                double valRound = NumericsUtils.StochasticRound(valReal, rng);
                Assert.True(valRound == Math.Floor(valReal) || valRound == Math.Ceiling(valReal));
            }
        }
Пример #5
0
        /// <summary>
        /// Select a subset of items from a superset of a given size.
        /// </summary>
        /// <param name="supersetCount">The size of the superset to select from.</param>
        /// <param name="rng">Random source.</param>
        /// <returns>An array of indexes that are the selected items.</returns>
        public int[] SelectSubset(int supersetCount, IRandomSource rng)
        {
            // Note. Ideally we'd return a sorted list of indexes to improve performance of the code that consumes them,
            // however, the sampling process inherently produces samples in randomized order, thus the decision of whether
            // to sort or not depends on the cost to the code using the samples. I.e. don't sort here!
            int selectionCount = (int)NumericsUtils.StochasticRound(supersetCount * _selectionProportion, rng);

            int[] idxArr = new int[selectionCount];
            DiscreteDistribution.SampleUniformWithoutReplacement(rng, supersetCount, idxArr);
            return(idxArr);
        }
Пример #6
0
    /// <summary>
    /// Creates a single randomly initialised genome.
    /// </summary>
    private NeatGenome <T> CreateGenome()
    {
        // Determine how many connections to create in the new genome, as a proportion of all possible connections
        // between the input and output nodes.
        int connectionCount = (int)NumericsUtils.StochasticRound(_connectionDefArr.Length * _connectionsProportion, _rng);

        // Ensure there is at least one connection.
        connectionCount = Math.Max(1, connectionCount);

        // Select a random subset of all possible connections between the input and output nodes.
        int[] sampleArr = new int[connectionCount];
        DiscreteDistribution.SampleUniformWithoutReplacement(
            _rng, _connectionDefArr.Length, sampleArr);

        // Sort the samples.
        // Note. This results in the neural net connections being sorted by sourceID then targetID.
        Array.Sort(sampleArr);

        // Create the connection gene arrays and populate them.
        var connGenes = new ConnectionGenes <T>(connectionCount);
        var connArr   = connGenes._connArr;
        var weightArr = connGenes._weightArr;

        for (int i = 0; i < sampleArr.Length; i++)
        {
            DirectedConnection cdef = _connectionDefArr[sampleArr[i]];

            connArr[i] = new DirectedConnection(
                cdef.SourceId,
                cdef.TargetId);

            weightArr[i] = _connWeightDist.Sample(_rng);
        }

        // Get create a new genome with a new ID, birth generation of zero.
        int id = _genomeIdSeq.Next();

        return(_genomeBuilder.Create(id, 0, connGenes));
    }
    private void CreateSpeciesOffspringSexual(
        Species <T>[] speciesArr,
        Species <T> species,
        DiscreteDistribution speciesDistUpdated,
        DiscreteDistribution?[] genomeDistArr,
        DiscreteDistribution genomeDist,
        int offspringCount,
        List <NeatGenome <T> > offspringList,
        double interspeciesMatingProportion,
        IRandomSource rng,
        out int offspringInterspeciesCount)
    {
        // Calc the number of offspring to create via inter-species sexual reproduction.
        int offspringCountSexualInter;

        if (interspeciesMatingProportion == 0.0)
        {
            offspringInterspeciesCount = offspringCountSexualInter = 0;
        }
        else
        {
            offspringInterspeciesCount = offspringCountSexualInter = (int)NumericsUtils.StochasticRound(interspeciesMatingProportion * offspringCount, rng);
        }

        // Calc the number of offspring to create via intra-species sexual reproduction.
        int offspringCountSexualIntra = offspringCount - offspringCountSexualInter;

        // Get genome list for the current species.
        var genomeList = species.GenomeList;

        // Produce the required number of offspring from intra-species sexual reproduction.
        for (int i = 0; i < offspringCountSexualIntra; i++)
        {
            // Select/sample parent A from the species.
            int genomeIdx     = DiscreteDistribution.Sample(rng, genomeDist);
            var parentGenomeA = genomeList[genomeIdx];

            // Create a new distribution with parent A removed from the set of possibilities.
            DiscreteDistribution genomeDistUpdated = genomeDist.RemoveOutcome(genomeIdx);

            // Select/sample parent B from the species.
            genomeIdx = DiscreteDistribution.Sample(rng, genomeDistUpdated);
            var parentGenomeB = genomeList[genomeIdx];

            // Create a child genome and add it to offspringList.
            var childGenome = _reproductionSexual.CreateGenome(parentGenomeA, parentGenomeB, rng);
            offspringList.Add(childGenome);
        }

        // Produce the required number of offspring from inter-species sexual reproduction.
        for (int i = 0; i < offspringCountSexualInter; i++)
        {
            // Select/sample parent A from the current species.
            int genomeIdx     = DiscreteDistribution.Sample(rng, genomeDist);
            var parentGenomeA = genomeList[genomeIdx];

            // Select another species to select parent B from.
            int         speciesIdx = DiscreteDistribution.Sample(rng, speciesDistUpdated);
            Species <T> speciesB   = speciesArr[speciesIdx];

            // Select parent B from species B.
            DiscreteDistribution genomeDistB = genomeDistArr[speciesIdx] !;
            genomeIdx = DiscreteDistribution.Sample(rng, genomeDistB);
            var parentGenomeB = speciesB.GenomeList[genomeIdx];

            // Ensure parentA is the fittest of the two parents.
            if (_fitnessComparer.Compare(parentGenomeA.FitnessInfo, parentGenomeB.FitnessInfo) < 0)
            {
                VariableUtils.Swap(ref parentGenomeA !, ref parentGenomeB !);
            }

            // Create a child genome and add it to offspringList.
            var childGenome = _reproductionSexual.CreateGenome(parentGenomeA, parentGenomeB, rng);
            offspringList.Add(childGenome);
        }
    }