/// <summary> /// This is used to crossover two parents to make a child /// </summary> /// <param name="parentA"></param> /// <param name="parentB"></param> private Genome(EvolutionConfig config, Genome parentA, Genome parentB) : this(config, false) { Genome moreFitParent = parentA.fitness > parentB.fitness ? parentA : parentB; Genome lessFitParent = parentA.fitness > parentB.fitness ? parentB : parentA; // Take all similar genes from the most fit parent, and randomly select disjoint genes IEnumerable<Gene> childGenes = moreFitParent.Genes.Where(item => lessFitParent.Genes.Exists(item2 => item2.InnovationNumber == item.InnovationNumber) || config.rng.NextDouble() > 0.50) .Union(lessFitParent.Genes.Where(item => !moreFitParent.Genes.Exists(item2 => item2.InnovationNumber == item.InnovationNumber) && config.rng.NextDouble() > 0.50)); // Set mutation rates to the most fit parent mutationRates = moreFitParent.mutationRates; // Create unique copies of genes foreach (Gene g in childGenes) Genes.Add((Gene)g.Clone()); // Copy parent A's start values startValues = new Dictionary<int,double>(moreFitParent.startValues); // Throw in parent B's extra start values foreach (var pair in lessFitParent.startValues) { if (!startValues.ContainsKey(pair.Key)) startValues.Add(pair.Key, pair.Value); } }
/// <summary> /// This breeds to parents to make a new child from a species offspring has a chance of being a clone of the parent /// </summary> /// <param name="config"></param> /// <param name="species"></param> /// <returns></returns> public static Genome BreedChild(EvolutionConfig config, Species species) { Genome child; // If the specie only contains one child, the species can't crossover if (species.genomes.Count == 1) child = (Genome) species.genomes.First().Clone(); else { Genome parentA = species.genomes.ElementAt(rng.Next(species.genomes.Count)); // Non-crossover chance if (rng.NextDouble() >= config.CrossOverRate) child = (Genome) parentA.Clone(); else { // Crossover Genome parentB = species.genomes.Where(g => g != parentA).ElementAt(rng.Next(species.genomes.Count - 1)); child = new Genome(config, parentA, parentB); } } // Mutate child.Mutate(); return child; }
/// <summary> /// Sets up a neural network for a /// </summary> /// <param name="config"></param> /// <param name="genes"></param> public NeuralNetwork(Genome genome) { // Copy genome gen = genome; smallestNode = null; int? smallestBackup = null; // Setup hash table hashTable = new Dictionary<int, int>(); int hashIndex = gen.evoConfig.InputNodeCount + 1 + gen.evoConfig.OutputNodeCount; // Select unique node values (Get the distinct values from both the NodeInputs and NodeOuputs) foreach (int n in genome.Genes.Select(g => g.NodeInput) .Union( genome.Genes.Select(g => g.NodeOutput)) .Union(Enumerable.Range(0, gen.evoConfig.InputNodeCount + 1 + gen.evoConfig.OutputNodeCount)) .Distinct()) { // Assign exact values if an input or outputnode if (IsInputOutputNode(genome.evoConfig, n)) hashTable.Add(n, n); else hashTable.Add(n, hashIndex++); } foreach (int n in genome.Genes.Select(g => g.NodeOutput)) { if (IsOutputNode(gen.evoConfig, n)) { if (!smallestBackup.HasValue || n < smallestBackup) smallestBackup = n; } else if (!smallestNode.HasValue || n < smallestNode) smallestNode = n; } if (!smallestNode.HasValue) smallestNode = smallestBackup; // Setup instances outputs = new double[genome.evoConfig.OutputNodeCount]; values = new double[hashTable.Count]; // Set the bias biasIndex = gen.evoConfig.InputNodeCount; values[biasIndex] = 1.0; // Sort the genes gen.Genes.Sort((a, b) => { // If the one out of the two are an output, make that the largest number bool isAOutput = IsOutputNode(gen.evoConfig, a.NodeOutput); if (isAOutput != IsOutputNode(gen.evoConfig, b.NodeOutput)) if (isAOutput) return 1; else return 0; // Otherwise sort by ouput node number if (a.NodeOutput > b.NodeOutput) return 1; else if (a.NodeOutput < b.NodeOutput) return -1; return 0; }); // Copy start values to array foreach (var pair in gen.startValues) if (hashTable.ContainsKey(pair.Key)) values[hashTable[pair.Key]] = pair.Value; }
private void AddGenomeToSpecies(Genome genome) { List<Species> possibleSpecies = new List<Species>(species); // Attempt to find a compatable species while (possibleSpecies.Count > 0) { // Select a random species from the list Species selectedSpecies = possibleSpecies[evoConfig.rng.Next(possibleSpecies.Count)]; // If the select species is within range of the compatability threshold add it to the species if (selectedSpecies.genomes.First() - genome < evoConfig.CompatablilityThresholdConstant) { selectedSpecies.Add(genome); return; } // Cross this species attempt off our list (literally, because its a list) possibleSpecies.Remove(selectedSpecies); } // We could not find a species, make a new one Species newSpecies = new Species(); // Add the genome to the species newSpecies.Add(genome); // Add the species to the species list species.Add(newSpecies); }