Example #1
0
        private List <NeatGenome <T> > CreateOffspring(
            Species <T>[] speciesArr,
            DiscreteDistribution speciesDist,
            DiscreteDistribution[] genomeDistArr,
            double interspeciesMatingProportion,
            IRandomSource rng)
        {
            // Calc total number of offspring to produce for the population as a whole.
            int offspringCount = speciesArr.Sum(x => x.Stats.OffspringCount);

            // Create an empty list to add the offspring to (with preallocated storage).
            var offspringList = new List <NeatGenome <T> >(offspringCount);

            // Loop the species.
            for (int speciesIdx = 0; speciesIdx < speciesArr.Length; speciesIdx++)
            {
                // Get the current species.
                Species <T> species = speciesArr[speciesIdx];

                // Get the DiscreteDistribution for genome selection within the current species.
                DiscreteDistribution genomeDist = genomeDistArr[speciesIdx];

                // Determine how many offspring to create through asexual and sexual reproduction.
                SpeciesStats stats = species.Stats;
                int          offspringCountAsexual = stats.OffspringAsexualCount;
                int          offspringCountSexual  = stats.OffspringSexualCount;

                // Special case: A species with a single genome marked for selection, cannot perform intra-species sexual reproduction.
                if (species.Stats.SelectionSizeInt == 1)
                {
                    // Note. here we assign all the sexual reproduction allocation to asexual reproduction. In principle
                    // we could still perform inter species sexual reproduction, but that complicates the code further
                    // for minimal gain.
                    offspringCountAsexual += offspringCountSexual;
                    offspringCountSexual   = 0;
                }

                // Create a copy of speciesDist with the current species removed from the set of possibilities.
                // Note. The remaining probabilities are normalised to sum to one.
                DiscreteDistribution speciesDistUpdated = speciesDist.RemoveOutcome(speciesIdx);

                // Create offspring from the current species.
                CreateSpeciesOffspringAsexual(
                    species, genomeDist, offspringCountAsexual, offspringList, rng);

                CreateSpeciesOffspringSexual(
                    speciesArr, species, speciesDistUpdated,
                    genomeDistArr, genomeDist,
                    offspringCountSexual, offspringList,
                    interspeciesMatingProportion, rng);
            }

            return(offspringList);
        }
        private NeatGenome <T> Create(
            NeatGenome <T> parent,
            IRandomSource rng,
            ref DiscreteDistribution mutationTypeDist)
        {
            // Determine the type of mutation to attempt.
            MutationType mutationTypeId = (MutationType)DiscreteDistribution.Sample(rng, mutationTypeDist);

            // Attempt to create a child genome using the selected mutation type.
            NeatGenome <T> childGenome = null;

            switch (mutationTypeId)
            {
            // Note. These subroutines will return null if they cannot produce a child genome,
            // e.g. 'delete connection' will not succeed if there is only one connection.
            case MutationType.ConnectionWeight:
                childGenome = _mutateWeightsStrategy.CreateChildGenome(parent, rng);
                break;

            case MutationType.AddNode:
                // FIXME: Reinstate.
                childGenome = _addNodeStrategy.CreateChildGenome(parent, rng);
                break;

            case MutationType.AddConnection:
                childGenome = _addConnectionStrategy.CreateChildGenome(parent, rng);
                break;

            case MutationType.DeleteConnection:
                childGenome = _deleteConnectionStrategy.CreateChildGenome(parent, rng);
                break;

            default:
                throw new Exception($"Unexpected mutationTypeId [{mutationTypeId}].");
            }

            if (null != childGenome)
            {
                return(childGenome);
            }

            // The chosen mutation type was not possible; remove that type from the set of possible types.
            mutationTypeDist = mutationTypeDist.RemoveOutcome((int)mutationTypeId);

            // Sanity test.
            if (0 == mutationTypeDist.Probabilities.Length)
            {   // This shouldn't be possible, hence this is an exceptional circumstance.
                // Note. Connection weight and 'add node' mutations should always be possible, because there should
                // always be at least one connection.
                throw new Exception("All types of genome mutation failed.");
            }
            return(null);
        }
        /// <summary>
        /// Cross specie mating.
        /// </summary>
        /// <param name="dist">DiscreteDistribution for selecting genomes in the current specie.</param>
        /// <param name="distArr">Array of DiscreteDistribution objects for genome selection. One for each specie.</param>
        /// <param name="rwlSpecies">DiscreteDistribution for selecting species. Based on relative fitness of species.</param>
        /// <param name="currentSpecieIdx">Current specie's index in _specieList</param>
        /// <param name="genomeList">Current specie's genome list.</param>
        private TGenome CreateOffspring_CrossSpecieMating(DiscreteDistribution dist,
                                                          DiscreteDistribution[] distArr,
                                                          DiscreteDistribution rwlSpecies,
                                                          int currentSpecieIdx,
                                                          IList<TGenome> genomeList)
        {
            // Select parent from current specie.
            int parent1Idx = dist.Sample();

            // Select specie other than current one for 2nd parent genome.
            DiscreteDistribution distSpeciesTmp = rwlSpecies.RemoveOutcome(currentSpecieIdx);
            int specie2Idx = distSpeciesTmp.Sample();
            
            // Select a parent genome from the second specie.
            int parent2Idx = distArr[specie2Idx].Sample();

            // Get the two parents to mate.
            TGenome parent1 = genomeList[parent1Idx];
            TGenome parent2 = _specieList[specie2Idx].GenomeList[parent2Idx];
            return parent1.CreateOffspring(parent2, _currentGeneration);
        }
        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.ProbabilisticRound(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);
            }
        }
Example #5
0
        /// <summary>
        /// Create the required number of offspring genomes, using specieStatsArr as the basis for selecting how
        /// many offspring are produced from each species.
        /// </summary>
        private List <TGenome> CreateOffspring(SpecieStats[] specieStatsArr, int offspringCount)
        {
            // Build a DiscreteDistribution for selecting species for cross-species reproduction.
            // While we're in the loop we also pre-build a DiscreteDistribution for each specie;
            // Doing this before the main loop means we have DiscreteDistributions available for
            // all species when performing cross-specie matings.
            int specieCount = specieStatsArr.Length;

            double[] specieFitnessArr      = new double[specieCount];
            DiscreteDistribution[] distArr = new DiscreteDistribution[specieCount];

            // Count of species with non-zero selection size.
            // If this is exactly 1 then we skip inter-species mating. One is a special case because for 0 the
            // species all get an even chance of selection, and for >1 we can just select normally.
            int nonZeroSpecieCount = 0;

            for (int i = 0; i < specieCount; i++)
            {
                // Array of probabilities for specie selection. Note that some of these probabilities can be zero, but at least one of them won't be.
                SpecieStats inst = specieStatsArr[i];
                specieFitnessArr[i] = inst._selectionSizeInt;

                if (0 == inst._selectionSizeInt)
                {
                    // Skip building a DiscreteDistribution for species that won't be selected from.
                    distArr[i] = null;
                    continue;
                }

                nonZeroSpecieCount++;

                // For each specie we build a DiscreteDistribution for genome selection within
                // that specie. Fitter genomes have higher probability of selection.
                List <TGenome> genomeList    = _specieList[i].GenomeList;
                double[]       probabilities = new double[inst._selectionSizeInt];
                for (int j = 0; j < inst._selectionSizeInt; j++)
                {
                    probabilities[j] = genomeList[j].EvaluationInfo.Fitness;
                }
                distArr[i] = new DiscreteDistribution(probabilities);
            }

            // Complete construction of DiscreteDistribution for specie selection.
            DiscreteDistribution rwlSpecies = new DiscreteDistribution(specieFitnessArr);

            // Produce offspring from each specie in turn and store them in offspringList.
            List <TGenome> offspringList = new List <TGenome>(offspringCount);

            for (int specieIdx = 0; specieIdx < specieCount; specieIdx++)
            {
                SpecieStats    inst       = specieStatsArr[specieIdx];
                List <TGenome> genomeList = _specieList[specieIdx].GenomeList;

                // Get DiscreteDistribution for genome selection.
                DiscreteDistribution dist = distArr[specieIdx];

                // --- Produce the required number of offspring from asexual reproduction.
                for (int i = 0; i < inst._offspringAsexualCount; i++)
                {
                    int     genomeIdx = DiscreteDistribution.Sample(_rng, dist);
                    TGenome offspring = genomeList[genomeIdx].CreateOffspring(_currentGeneration);
                    offspringList.Add(offspring);
                }
                _stats._asexualOffspringCount += (ulong)inst._offspringAsexualCount;

                // --- Produce the required number of offspring from sexual reproduction.
                // Cross-specie mating.
                // If nonZeroSpecieCount is exactly 1 then we skip inter-species mating. One is a special case because
                // for 0 the  species all get an even chance of selection, and for >1 we can just select species normally.
                int crossSpecieMatings = nonZeroSpecieCount == 1 ? 0 :
                                         (int)NumericsUtils.ProbabilisticRound(_eaParams.InterspeciesMatingProportion
                                                                               * inst._offspringSexualCount, _rng);
                _stats._sexualOffspringCount       += (ulong)(inst._offspringSexualCount - crossSpecieMatings);
                _stats._interspeciesOffspringCount += (ulong)crossSpecieMatings;

                // An index that keeps track of how many offspring have been produced in total.
                int matingsCount = 0;
                for (; matingsCount < crossSpecieMatings; matingsCount++)
                {
                    TGenome offspring = CreateOffspring_CrossSpecieMating(dist, distArr, rwlSpecies, specieIdx, genomeList);
                    offspringList.Add(offspring);
                }

                // For the remainder we use normal intra-specie mating.
                // Test for special case - we only have one genome to select from in the current specie.
                if (1 == inst._selectionSizeInt)
                {
                    // Fall-back to asexual reproduction.
                    for (; matingsCount < inst._offspringSexualCount; matingsCount++)
                    {
                        int     genomeIdx = DiscreteDistribution.Sample(_rng, dist);
                        TGenome offspring = genomeList[genomeIdx].CreateOffspring(_currentGeneration);
                        offspringList.Add(offspring);
                    }
                }
                else
                {
                    // Remainder of matings are normal within-specie.
                    for (; matingsCount < inst._offspringSexualCount; matingsCount++)
                    {
                        // Select parent 1.
                        int     parent1Idx = DiscreteDistribution.Sample(_rng, dist);
                        TGenome parent1    = genomeList[parent1Idx];

                        // Remove selected parent from set of possible outcomes.
                        DiscreteDistribution distTmp = dist.RemoveOutcome(parent1Idx);

                        // Test for existence of at least one more parent to select.
                        if (0 != distTmp.Probabilities.Length)
                        {   // Get the two parents to mate.
                            int     parent2Idx = DiscreteDistribution.Sample(_rng, distTmp);
                            TGenome parent2    = genomeList[parent2Idx];
                            TGenome offspring  = parent1.CreateOffspring(parent2, _currentGeneration);
                            offspringList.Add(offspring);
                        }
                        else
                        {   // No other parent has a non-zero selection probability (they all have zero fitness).
                            // Fall back to asexual reproduction of the single genome with a non-zero fitness.
                            TGenome offspring = parent1.CreateOffspring(_currentGeneration);
                            offspringList.Add(offspring);
                        }
                    }
                }
            }

            _stats._totalOffspringCount += (ulong)offspringCount;
            return(offspringList);
        }