public ReproduceAndReplace_Node(ScoredDistribution <Organism> scoredDistribution_organisms, Species new_species) { this.scoredDistribution_organisms = scoredDistribution_organisms; this.new_species = new_species; }
/// <summary> /// Performs speciation, adjusting fitness sums, culling, crossover, and mutation, to generate the next generation of Neural Networks /// </summary> public void Select() { speciesList = new List <Species>(); foreach (NeuralNetwork NN in Networks) { bool foundSpecies = false; foreach (Species species in speciesList) { if (NeuralNetwork.EvolutionaryDistance(species.networks.ElementAt(0), NN, innovationNumbers) < SpeciatingThreshold) { species.networks.Add(NN); foundSpecies = true; break; } } if (!foundSpecies) { speciesList.Add(new Species(NN)); } } //Console.WriteLine("speciesList Count after speciating: " + speciesList.Count); //Console.WriteLine("Pop Consistency: " + isConsistent()); foreach (Species species in speciesList) { species.networks.Sort((NN1, NN2) => NN2.Fitness.CompareTo(NN1.Fitness)); int kill = (int)(Math.Ceiling(species.networks.Count() * killRate)); int total = species.networks.Count(); for (int i = species.networks.Count() - 1; i > total - 1 - kill; i--) { species.networks.RemoveAt(i); } for (int i = 0; i < species.networks.Count(); i++) { species.adjustedFitnessSum += species.networks.ElementAt(i).Fitness / (species.networks.Count); } } speciesList.RemoveAll(x => x.networks.Count < 3); //Console.WriteLine("speciesList Count after killing: " + speciesList.Count); //Console.WriteLine("Pop Consistency: " + isConsistent()); int numSelectionBreed = (int)(.75 * Size); speciesList.Sort((species1, species2) => species2.adjustedFitnessSum.CompareTo(species1.adjustedFitnessSum)); double sharedFitnessTotal = 0; for (int i = 0; i < speciesList.Count / 3; i++) { Species species = speciesList.ElementAt(i); sharedFitnessTotal += species.adjustedFitnessSum; } //Console.WriteLine("speciesList Count after adjusting fitness sums: " + speciesList.Count); //Console.WriteLine("Pop Consistency: " + isConsistent()); List <NeuralNetwork> childrenNetworks = new List <NeuralNetwork>(); Random rand = new Random(); for (int i = 0; i < speciesList.Count / 3; i++) { Species species = speciesList.ElementAt(i); for (int j = 0; j < numSelectionBreed * (species.adjustedFitnessSum / sharedFitnessTotal); j++) { //Console.WriteLine("Pop Consistency: " + isConsistent()); NeuralNetwork NN1 = species.networks.ElementAt(rand.Next(species.networks.Count)); NeuralNetwork NN2 = species.networks.ElementAt(rand.Next(species.networks.Count)); NeuralNetwork Child = NeuralNetwork.Crossover(NN1, NN2, innovationNumbers); Child.RandomMutation(); //Child.DisplayOutputConnections(); childrenNetworks.Add(Child); //Console.WriteLine("Pop Consistency: " + isConsistent()); //Console.WriteLine(); } } //Console.WriteLine(); //Console.WriteLine("speciesList Count after selection breeding: "+ speciesList.Count); //Console.WriteLine("Pop Consistency: " + isConsistent()); //Console.WriteLine(); Networks.Sort((NN1, NN2) => NN2.Fitness.CompareTo(NN1.Fitness)); for (int i = 0; i < 5; i++) { childrenNetworks.Add(Networks.ElementAt(i)); } int numRandomBreed = Networks.Count - childrenNetworks.Count; for (int i = 0; i < numRandomBreed; i++) { Species randSpecies = speciesList[rand.Next(speciesList.Count)]; NeuralNetwork randNN1 = randSpecies.networks[rand.Next(randSpecies.networks.Count)]; NeuralNetwork randNN2 = randSpecies.networks[rand.Next(randSpecies.networks.Count)]; NeuralNetwork child = NeuralNetwork.Crossover(randNN1, randNN2, innovationNumbers); child.RandomMutation(); //child.DisplayOutputConnections(); childrenNetworks.Add(child); } //Console.WriteLine(); //Console.WriteLine("speciesList Count after random breeding: " + speciesList.Count); //Console.WriteLine("Pop Consistency: " + isConsistent()); //Console.WriteLine(); Networks = new List <NeuralNetwork>(childrenNetworks); //Console.WriteLine("total child networks after selection: " + childrenNetworks.Count); //Console.WriteLine("Pop Consistency: " + isConsistent()); }
/// <summary> /// Reproduces the surviving species based on their fitness scores. Chooses the organisms in the species to mate based on fitness scores as well. Replaces the previous generation /// with the newly created organisms. Removes extinct species if necessary. Adjusts compatibility distance after replacement. /// See <see cref="NEAT.NEATClient.Evolve"/> before using! /// </summary> /// <remarks> /// Decides the amount of offspring (nk) each species (k) should be allotted via the following equation: /// <para/> /// nk = P * (Fk / Ft) /// <para/> /// Where: /// <list type="bullet"> /// <item>k: The species.</item> /// <item>nk: The number of new organisms for species k in the next generation.</item> /// <item>P: The desired new population count.</item> /// <item>Fk: The average fitness score of the species.</item> /// <item>Ft: The sum of all fitness score averages of every species.</item> /// </list> /// </remarks> public void ReproduceAndReplace() { double total_speciesFitness = Species.Sum(x => x.AverageFitnessScore); Dictionary <Species, ReproduceAndReplace_Node> stored_distributionsSpecies = new Dictionary <Species, ReproduceAndReplace_Node>(Species.Count); List <Organism> next_generation = new List <Organism>(NumOrganisms); //All of the new organisms. HashSet <Species> next_species = new HashSet <Species>(Species.Count); #region Reproduction foreach (Species species in Species) { //Calculate the number of organisms every species will have: int num_alloted_offspring = (int)(NumOrganisms * (species.AverageFitnessScore / total_speciesFitness)); //Prepare new species for placement: Species creation_species = new Species(); next_species.Add(creation_species); //Prepare ScoredDistribution for selecting organisms to mate: ScoredDistribution <Organism> internal_organisms = new ScoredDistribution <Organism>(species.Size, Pedigree.Random); foreach (Organism organism in species) { internal_organisms.Add(organism, organism.FitnessScore); } stored_distributionsSpecies.Add(species, new ReproduceAndReplace_Node(internal_organisms, creation_species)); //Actaully mate the organisms: for (int i = 0; i < num_alloted_offspring; ++i) { Organism random_organism_1 = internal_organisms.ChooseValue(); Organism random_organism_2 = internal_organisms.ChooseValue(random_organism_1); //We don't want any self-replication... if (random_organism_2 == null) { random_organism_2 = random_organism_1; //Unless that's the only option ;) Only happens when the organism is the only one in the species. } Organism baby = new Organism(random_organism_1.Genome.Crossover(random_organism_1.FitnessScore, random_organism_2.Genome, random_organism_2.FitnessScore, Pedigree.Random)); next_generation.Add(baby); creation_species.AddOrganism(baby); } } while (next_generation.Count < NumOrganisms) //We need more organisms, give it to some random species. Super rare that this doesn't happen. { ReproduceAndReplace_Node chosen_last_node = stored_distributionsSpecies[Species.RandomValue(Pedigree.Random)]; ScoredDistribution <Organism> last_round_distribution = chosen_last_node.scoredDistribution_organisms; Species last_round_species = chosen_last_node.new_species; Organism random_organism_1 = last_round_distribution.ChooseValue(); Organism random_organism_2 = last_round_distribution.ChooseValue(random_organism_1); //We don't want any self-replication... if (random_organism_2 == null) { random_organism_2 = random_organism_1; //Unless that's the only option ;) Only happens when the organism is the only one in the species. } Organism baby = new Organism(random_organism_1.Genome.Crossover(random_organism_1.FitnessScore, random_organism_2.Genome, random_organism_2.FitnessScore, Pedigree.Random)); next_generation.Add(baby); last_round_species.AddOrganism(baby); } #endregion Reproduction #region Replacement //Organisms: Organisms.Clear(); Organisms.AddRange(next_generation); //Species: Species.Clear(); foreach (Species species in next_species) { Species.Add(species); } #endregion Replacement RemoveExtinctions(); CompatibilityDistance += CD_function.Invoke(Species.Count); }
/// <summary> /// Removes all stored extinct species (species with no organisms). See <see cref="NEAT.NEATClient.Evolve"/> before using! /// </summary> public void RemoveExtinctions() { Species.RemoveWhere(x => x.Size == 0); }
/// <summary> /// Separates the current organisms into the correct species. Makes new species and deletes extinct species as needed. See <see cref="NEAT.NEATClient.Evolve"/> before using! /// </summary> public void Speciate() { foreach (Organism organism in Organisms) { bool found_species = false; foreach (Species species in Species) { Organism random_organism = species.GetRandomOrganism(Pedigree.Random, organism); if (random_organism == null) //The organism we're at is the only organism in the species we're at. See if we should leave it in this species. { bool kill_species = false; IEnumerable <Species> all_other_species = Species.Where(x => x != species); foreach (Species other_species in all_other_species) { Organism other_random_organism = other_species.GetRandomOrganism(Pedigree.Random); //No need to exclude the organism because it can't be here. if (organism.Genome.Distance(other_random_organism.Genome) < CompatibilityDistance) //The organism can fit in another species, put it there. { organism.Species.RemoveOrganism(organism); other_species.AddOrganism(organism); kill_species = true; break; } } if (kill_species) //This species no longer has any organisms, it is now extinct. { Species.Remove(species); } found_species = true; break; } if (organism.Genome.Distance(random_organism.Genome) < CompatibilityDistance) { if (organism.Species != random_organism.Species) //If the species to set is actually different. { Species original_species = organism.Species; original_species?.RemoveOrganism(organism); species.AddOrganism(organism); if (original_species?.Size == 0) //This species just went extinct. { Species.Remove(original_species); } } found_species = true; break; } } if (!found_species) { Species original_species = organism.Species; original_species?.RemoveOrganism(organism); Species new_species = new Species(); Species.Add(new_species); new_species.AddOrganism(organism); if (original_species?.Size == 0) //This species just went extinct. { Species.Remove(original_species); } } } }
/// <summary> /// Breed /// </summary> private void Breed() { // Logs Setup int weightMutationNb = 0; int addConnectionNb = 0; int addNodeNb = 0; int enableDisableConnectionNb = 0; _mutationLogs = ""; while (_nextEvaluationGenomes.Count() < _config.populationSize) { Genome child = null; Genome mom = null; Genome dad = null; // Get Child Species species = null; int maxToKeep = ((_config.populationSize * _config.percentageToKeep) / 100) - 1; if (_config.species) { species = GetRandomSpecies(_r); } if (_config.crossover) { if (species != null) { mom = GetRandomGenome(species, _r); dad = GetRandomGenome(species, _r); } else { mom = _genomes[UnityEngine.Random.Range(0, maxToKeep)]; dad = _genomes[UnityEngine.Random.Range(0, maxToKeep)]; } // Crossover between Mom & Dad child = mom.Fitness >= dad.Fitness ? Genome.Crossover(mom, dad, _r, _config.disabledConnectionInheritChance) : Genome.Crossover(dad, mom, _r, _config.disabledConnectionInheritChance); } else { child = species != null ? new Genome(GetRandomGenome(species, _r)) : new Genome(_genomes[UnityEngine.Random.Range(0, maxToKeep)]); } // Weights Mutation if ((float)_r.NextDouble() < _config.mutationRate) { child.WeightsMutation(_r); weightMutationNb++; } if (_config.genomeMutations) { // Add Connection Mutation if ((float)_r.NextDouble() < _config.addConnectionRate) { // If for Logs if (child.AddConnectionMutation(_r, _connectionInnovation, 10)) { addConnectionNb++; } } // Add Node Mutation if ((float)_r.NextDouble() < _config.addNodeRate) { child.AddNodeMutation(_r, _connectionInnovation, _nodeInnovation); addNodeNb++; } // Enable/Disable a Random Connection if ((float)_r.NextDouble() < _config.enableDisableRate) { // If for Logs if (child.EnableOrDisableRandomConnection()) { enableDisableConnectionNb++; } } } // Add Child to Next Evaluation Genomes _nextEvaluationGenomes.Add(child); } _mutationLogs += string.Format( "Weights Mutation: {0}, Add Connection: {1}, Add Node: {2}, Enable/Disable Connection: {3}\nCrossover is {4}, Genome Mutations is {5}, Species is {6}", weightMutationNb, addConnectionNb, addNodeNb, enableDisableConnectionNb, _config.crossover, _config.genomeMutations, _config.species ); _genomes.Clear(); _genomes = new List <Genome>(_nextEvaluationGenomes); _nextEvaluationGenomes = new List <Genome>(); }
/// <summary> /// Eliminate the species with its genomes. /// </summary> private void EliminateSpecies(Species speciesTarget) { Genomes.RemoveAll(x => speciesTarget.Genomes.Contains(x)); SpeciesCtrl.SpeciesList.Remove(speciesTarget); }