/// <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> /// Main constructor for evolution. Requires a configuration instance /// </summary> /// <param name="config"></param> public Evolution(EvolutionConfig config) { // Setup new lists genomes = new List<Genome>(); species = new List<Species>(); // Reset basic variables evaluationIndex = 0; speciesFitnessSum = 0; generationNumber = 0; topScore = 0; // Set the configuration evoConfig = config; // Create new random genomes for (int i = 0; i < config.PopulationSize; i++) genomes.Add(new Genome(config)); // Mutate each genenome, add add them to a species foreach (Genome g in genomes) { g.Mutate(); AddGenomeToSpecies(g); } // Setup netwrok evaluationNetwork = new NeuralNetwork(genomes[0]); }
/// <summary> /// Call this function to set the default gene values (still needs an inputNode and outputNode) /// </summary> /// <param name="input"></param> /// <param name="output"></param> public Gene(EvolutionConfig config, int input, int output) { // Defaults NodeInput = input; NodeOutput = output; ConnectionEnabled = true; ConnectionWeight = 1.0; InnovationNumber = Innovation.NewInnovationNumber; }
/// <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; }
public static bool IsOutputNode(EvolutionConfig config, int n) { return (n >= config.InputNodeCount + 1 && IsInputOutputNode(config, n)); }
public static bool IsInputOutputNode(EvolutionConfig config, int n) { return (n < config.InputNodeCount + 1 + config.OutputNodeCount); }