/// <summary> /// Runs each Neural Network of the population through the fitness function and assigns the fitnesses. /// Overloaded for running on multiple threads. default is unthreaded. /// </summary> public void Run() { Dictionary <int, double> fitnesses = new Dictionary <int, double>(); double totalfitness = 0; if (threaded) { Thread thread1 = new Thread(() => { for (int i = 0; i < Networks.Count / 4; i++) { NeuralNetwork NN = Networks.ElementAt(i); double fitness = run(NN); totalfitness += fitness; lock (fitnesses) { fitnesses.Add(i, fitness); } //Console.WriteLine(i + " -> " + fitness); } }); Thread thread2 = new Thread(() => { for (int i = Networks.Count / 4; i < Networks.Count / 2; i++) { NeuralNetwork NN = Networks.ElementAt(i); double fitness = run(NN); totalfitness += fitness; lock (fitnesses) { fitnesses.Add(i, fitness); } //Console.WriteLine(i + " -> " + fitness); } }); Thread thread3 = new Thread(() => { for (int i = Networks.Count / 2; i < 3 * Networks.Count / 4; i++) { NeuralNetwork NN = Networks.ElementAt(i); double fitness = run(NN); totalfitness += fitness; lock (fitnesses) { fitnesses.Add(i, fitness); } //Console.WriteLine(i + " -> " + fitness); } }); Thread thread4 = new Thread(() => { for (int i = 3 * Networks.Count / 4; i < Networks.Count; i++) { NeuralNetwork NN = Networks.ElementAt(i); double fitness = run(NN); totalfitness += fitness; lock (fitnesses) { fitnesses.Add(i, fitness); } //Console.WriteLine(i + " -> " + fitness); } }); thread1.Start(); thread2.Start(); thread3.Start(); thread4.Start(); thread1.Join(); thread2.Join(); thread3.Join(); thread4.Join(); } else { int count = 0; foreach (NeuralNetwork NN in Networks) { double fitness = run(NN); totalfitness += fitness; fitnesses.Add(count, fitness); //Console.WriteLine(count + " -> " + fitness); count++; } } AvgPopFitness = totalfitness / Networks.Count; BestNetwork = null; for (int i = 0; i < Networks.Count(); i++) { fitnesses.TryGetValue(i, out double fitness); if (BestNetwork == null || fitness > BestNetwork.Fitness) { BestNetwork = Networks.ElementAt(i); } Networks.ElementAt(i).Fitness = fitness; } //Console.WriteLine("Run: " + isConsistent()); }
/// <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()); }