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); } }
/// <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); }