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