/** Assign the individual into a species, if not found, create a new one */ public void Speciate(IEvolutionState state, Individual ind) { NEATIndividual neatInd = (NEATIndividual)ind; // For each individual, search for a subspecies it is compatible to if (Subspecies.Count == 0) // not subspecies available, create the // first species { NEATSubspecies newSubspecies = (NEATSubspecies)SubspeciesPrototype.EmptyClone(); newSubspecies.Reset(); Subspecies.Add(newSubspecies); newSubspecies.AddNewGenIndividual(neatInd); } else { bool found = false; foreach (NEATSubspecies s in Subspecies) { NEATIndividual represent = (NEATIndividual)s.NewGenerationFirst(); if (represent == null) { represent = (NEATIndividual)s.First(); } // found compatible subspecies, add this individual to it if (Compatibility(neatInd, represent) < CompatThreshold) { s.AddNewGenIndividual(neatInd); found = true; // change flag break; // search is over, quit loop } } // if we didn't find a match, create a new subspecies if (!found) { NEATSubspecies newSubspecies = (NEATSubspecies)SubspeciesPrototype.EmptyClone(); newSubspecies.Reset(); Subspecies.Add(newSubspecies); newSubspecies.AddNewGenIndividual(neatInd); } } }
/** * Breed a new generation of population, this is done by first figure the * expected offsprings for each subspecies, and then calls each subspecies * to reproduce. */ public void BreedNewPopulation(IEvolutionState state, int subpop, int thread) { // see epoch method in Population IList <Individual> inds = state.Population.Subpops[subpop].Individuals; ClearEvaluationFlag(inds); // clear the innovation information of last generation Innovations.Clear(); // we also ignore the code for competitive coevolution stagnation // detection // Use Species' ages to modify the objective fitness of organisms // in other words, make it more fair for younger species // so they have a chance to take hold // Also penalize stagnant species // Then adjust the fitness using the species size to "share" fitness // within a species. // Then, within each Species, mark for death // those below survivalThresh * average foreach (NEATSubspecies s in Subspecies) { s.AdjustFitness(state, DropoffAge, AgeSignificance); s.SortIndividuals(); s.UpdateSubspeciesMaxFitness(); s.MarkReproducableIndividuals(SurvivalThreshold); } // count the offspring for each subspecies CountOffspring(state, subpop); // sort the subspecies use extra list based on the max fitness // these need to use original fitness, descending order // BRS: Using LINQ instead of IComparer IList <NEATSubspecies> sortedSubspecies = Subspecies .OrderByDescending(s => s.Individuals[0].Fitness) .ToList(); // Check for population-level stagnation code PopulationStagnation(state, subpop, sortedSubspecies); // Check for stagnation if there is stagnation, perform delta-coding // TODO: fix weird constant if (HighestLastChanged >= DropoffAge + 5) { DeltaCoding(state, subpop, sortedSubspecies); } // STOLEN BABIES: The system can take expected offspring away from // worse species and give them to superior species depending on // the system parameter babies_stolen (when babies_stolen > 0) else if (BabiesStolen > 0) { StealBabies(state, thread, subpop, sortedSubspecies); } // Kill off all Individual marked for death. The remainder // will be allowed to reproduce. // NOTE this result the size change of individuals in each subspecies // however, it doesn't effect the individuals for the whole neat // population foreach (NEATSubspecies s in sortedSubspecies) { s.RemovePoorFitnessIndividuals(); } // Reproduction // Perform reproduction. Reproduction is done on a per-Species // basis. (So this could be paralellized potentially.) // we do this with sortedSubspecies instead of subspecies // this is due to the fact that new subspecies could be created during // the reproduction period // thus, the sortedSubspecies are guarantee to contain all the old // subspecies foreach (NEATSubspecies s in sortedSubspecies) { s.NewGenIndividuals.Clear(); } foreach (NEATSubspecies s in sortedSubspecies) { s.Reproduce(state, thread, subpop, sortedSubspecies); } // Remove all empty subspecies and age ones that survive // As this happens, create master individuals list for the new // generation // first age the old subspecies foreach (NEATSubspecies s in sortedSubspecies) { s.Age++; } IList <NEATSubspecies> remainSubspecies = new List <NEATSubspecies>(); IList <Individual> newGenIndividuals = new List <Individual>(); foreach (NEATSubspecies s in Subspecies) { if (s.HasNewGeneration()) { // add to the remaining subspecies remainSubspecies.Add(s); s.ToNewGeneration(); // add to the new generation population ((List <Individual>)newGenIndividuals).AddRange(s.Individuals); } } // replace the old stuff Subspecies = remainSubspecies; state.Population.Subpops[subpop].Individuals = newGenIndividuals; }