/** Perform a delta coding. */ public void DeltaCoding(IEvolutionState state, int subpop, IList <NEATSubspecies> sortedSubspecies) { HighestLastChanged = 0; int popSize = state.Population.Subpops[subpop].InitialSize; int halfPop = popSize / 2; NEATSubspecies bestFitnessSubspecies = sortedSubspecies[0]; // the first individual of the first subspecies can have 1/2 pop size // offsprings ((NEATIndividual)bestFitnessSubspecies.First()).SuperChampionOffspring = halfPop; // the first subspecies can have 1/2 pop size offspring bestFitnessSubspecies.ExpectedOffspring = halfPop; bestFitnessSubspecies.AgeOfLastImprovement = bestFitnessSubspecies.Age; if (sortedSubspecies.Count >= 2) { // the second subspecies can have the other half pop size ((NEATIndividual)sortedSubspecies[1].First()).SuperChampionOffspring = popSize - halfPop; sortedSubspecies[1].ExpectedOffspring = popSize - halfPop; sortedSubspecies[1].AgeOfLastImprovement = sortedSubspecies[1].Age; // the remainder subspecies has 0 offsprings for (int i = 2; i < sortedSubspecies.Count; ++i) { sortedSubspecies[i].ExpectedOffspring = 0; } } else { ((NEATIndividual)bestFitnessSubspecies.First()).SuperChampionOffspring += popSize - halfPop; bestFitnessSubspecies.ExpectedOffspring = popSize - halfPop; } }
/** * Where the actual reproduce is happening, it will grab the candidate * parents, and calls the crossover or mutation method on these parents * individuals. */ public bool Reproduce(IEvolutionState state, int thread, int subpop, IList <NEATSubspecies> sortedSubspecies) { if (ExpectedOffspring > 0 && Individuals.Count == 0) { state.Output.Fatal("Attempt to reproduce out of empty subspecies"); return(false); } if (ExpectedOffspring > state.Population.Subpops[subpop].InitialSize) { state.Output.Fatal("Attempt to reproduce too many individuals"); return(false); } NEATSpecies species = (NEATSpecies)state.Population.Subpops[subpop].Species; // bestIndividual of the 'this' specie is the first element of the // species // note, we already sort the individuals based on the fitness (not sure // if this is still correct to say) NEATIndividual bestIndividual = (NEATIndividual)First(); // create the designated number of offspring for the Species one at a // time bool bestIndividualDone = false; for (int i = 0; i < ExpectedOffspring; ++i) { NEATIndividual newInd; if (bestIndividual.SuperChampionOffspring > 0) { newInd = (NEATIndividual)bestIndividual.Clone(); // Most super champion offspring will have their connection // weights mutated only // The last offspring will be an exact duplicate of this super // champion // Note: Super champion offspring only occur with stolen babies! // Settings used for published experiments did not use this if (bestIndividual.SuperChampionOffspring > 1) { if (state.Random[thread].NextBoolean(0.8) || species.MutateAddLinkProb.Equals(0.0)) { newInd.MutateLinkWeights(state, thread, species, species.WeightMutationPower, 1.0, NEATSpecies.MutationType.GAUSSIAN); } else { // Sometime we add a link to a superchamp newInd.CreateNetwork(); // make sure we have the network newInd.MutateAddLink(state, thread); } } if (bestIndividual.SuperChampionOffspring == 1) { if (bestIndividual.PopChampion) { newInd.PopChampionChild = true; newInd.HighFit = bestIndividual.Fitness.Value; } } bestIndividual.SuperChampionOffspring--; } else if (!bestIndividualDone && ExpectedOffspring > 5) { newInd = (NEATIndividual)bestIndividual.Clone(); bestIndividualDone = true; } // Decide whether to mate or mutate // If there is only one individual, then always mutate else if (state.Random[thread].NextBoolean(species.MutateOnlyProb) || Individuals.Count == 1) { // Choose the random parent int parentIndex = state.Random[thread].NextInt(Individuals.Count); Individual parent = Individuals[parentIndex]; newInd = (NEATIndividual)parent.Clone(); newInd.DefaultMutate((EvolutionState)state, thread); } else // Otherwise we should mate { // random choose the first parent int parentIndex = state.Random[thread].NextInt(Individuals.Count); NEATIndividual firstParent = (NEATIndividual)Individuals[parentIndex]; NEATIndividual secondParent; // Mate within subspecies, choose random second parent if (state.Random[thread].NextBoolean(1.0 - species.InterspeciesMateRate)) { parentIndex = state.Random[thread].NextInt(Individuals.Count); secondParent = (NEATIndividual)Individuals[parentIndex]; } else // Mate outside subspecies { // Select a random species NEATSubspecies randomSubspecies = this; // Give up if you cant find a different Species int giveUp = 0; while (randomSubspecies == this && giveUp < 5) { // Choose a random species tending towards better // species double value = state.Random[thread].NextGaussian() / 4; if (value > 1.0) { value = 1.0; } // This tends to select better species int upperBound = (int)Math.Floor(value * (sortedSubspecies.Count - 1.0) + 0.5); int index = 0; while (index < upperBound) { index++; } randomSubspecies = sortedSubspecies[index]; giveUp++; } secondParent = (NEATIndividual)randomSubspecies.First(); } newInd = firstParent.Crossover(state, thread, secondParent); // Determine whether to mutate the baby's Genome // This is done randomly or if the parents are the same // individual if (state.Random[thread].NextBoolean(1.0 - species.MateOnlyProb) || firstParent == secondParent || species.Compatibility(firstParent, secondParent).Equals(0.0)) { newInd.DefaultMutate((EvolutionState)state, thread); } } newInd.SetGeneration(state); newInd.CreateNetwork(); // Add the new individual to its proper subspecies // this could create new subspecies species.Speciate(state, newInd); } return(true); }
/** Steal the babies from champion subspecies. */ public void StealBabies(IEvolutionState state, int thread, int subpop, IList <NEATSubspecies> sortedSubspecies) { // Take away a constant number of expected offspring from the worst few // species int babiesAlreadyStolen = 0; for (int i = sortedSubspecies.Count - 1; i >= 0 && babiesAlreadyStolen < BabiesStolen; i--) { NEATSubspecies subs = sortedSubspecies[i]; if (subs.Age > 5 && subs.ExpectedOffspring > 2) { // This subspecies has enough to finish off the stolen pool int babiesNeeded = BabiesStolen - babiesAlreadyStolen; if (subs.ExpectedOffspring - 1 >= babiesNeeded) { subs.ExpectedOffspring -= babiesNeeded; babiesAlreadyStolen = BabiesStolen; } // Not enough here to complete the pool of stolen, then leave // one individual // for that subspecies else { babiesAlreadyStolen += subs.ExpectedOffspring - 1; subs.ExpectedOffspring = 1; } } } // Mark the best champions of the top subspecies to be the super // champions // who will take on the extra offspring for cloning or mutant cloning // Determine the exact number that will be given to the top three // They get, in order, 1/5 1/5 and 1/10 of the already stolen babies int[] quote = new int[3]; quote[0] = quote[1] = BabiesStolen / 5; quote[2] = BabiesStolen / 10; int quoteIndex = 0; foreach (var subs in sortedSubspecies) { // Don't give to dying species even if they are champions if (subs.TimeSinceLastImproved() <= DropoffAge) { if (quoteIndex < quote.Length) { if (babiesAlreadyStolen > quote[quoteIndex]) { ((NEATIndividual)subs.First()).SuperChampionOffspring = quote[quoteIndex]; subs.ExpectedOffspring += quote[quoteIndex]; babiesAlreadyStolen -= quote[quoteIndex]; } quoteIndex++; } else if (quoteIndex >= quote.Length) { // Randomize a little which species get boosted by a super // champion if (state.Random[thread].NextBoolean(.9)) { if (babiesAlreadyStolen > 3) { ((NEATIndividual)subs.First()).SuperChampionOffspring = 3; subs.ExpectedOffspring += 3; babiesAlreadyStolen -= 3; } else { ((NEATIndividual)subs.First()).SuperChampionOffspring = babiesAlreadyStolen; subs.ExpectedOffspring += babiesAlreadyStolen; babiesAlreadyStolen = 0; } } } // assiged all the stolen babies if (babiesAlreadyStolen == 0) { break; } } } // If any stolen babies aren't taken, give them to species #1's champion if (babiesAlreadyStolen > 0) { state.Output.Message("Not all stolen babies assigned, giving to the best subspecies"); NEATSubspecies subs = Subspecies[0]; ((NEATIndividual)subs.First()).SuperChampionOffspring += babiesAlreadyStolen; subs.ExpectedOffspring += babiesAlreadyStolen; babiesAlreadyStolen = 0; } }