/// <summary> /// This constructor copys a gene and then updates the inputs and outputs /// </summary> /// <param name="gene"></param> private Gene(Gene gene) { NodeInput = gene.NodeInput; NodeOutput = gene.NodeOutput; ConnectionEnabled = gene.ConnectionEnabled; ConnectionWeight = gene.ConnectionWeight; InnovationNumber = gene.InnovationNumber; }
/// <summary> /// This method adds a single new node as a mutation and handles a connection 'split'. /// </summary> private void MutateAddNode() { // Find an available connection to modify // Get the list of available genes to mutate Gene[] availableGeneArray = Genes.Where(item => item.ConnectionEnabled).ToArray(); if (availableGeneArray.Count() == 0) return; Gene oldGene = availableGeneArray[rng.Next(availableGeneArray.Count())]; // Create a new node (find the maximum node value and add it) int newNodeIndex = Math.Max(Genes.Select(g => g.NodeInput).Union(Genes.Select(g => g.NodeOutput)).Max(), evoConfig.InputNodeCount + evoConfig.OutputNodeCount) + 1; // Add a new start value if it does not yet exist if (!startValues.ContainsKey(newNodeIndex)) startValues.Add(newNodeIndex, 2 - evoConfig.rng.NextDouble() * 4); // First gene (connection) copys the original, but is given an new innovation number Gene g1 = (Gene) oldGene.Clone(); g1.NodeOutput = newNodeIndex; g1.InnovationNumber = Innovation.NewInnovationNumber; // Second connection is treated as a passthrough (with a sigmoid function) Gene g2 = new Gene(evoConfig, newNodeIndex, oldGene.NodeOutput); // Disable the oldGene oldGene.ConnectionEnabled = false; // Add new genes to the list Genes.Add(g1); Genes.Add(g2); }
/// <summary> /// This method adds a single new gene (connection) as a mutation. /// </summary> private void MutateAddGene(bool biasOnly = false) { IEnumerable<int> allNodes = Genes.Select(g => g.NodeInput) .Union( Genes.Select(g => g.NodeOutput)) .Distinct() .Where(n => !(NeuralNetwork.IsInputOutputNode(evoConfig, n))); List<int> availableInputNodeList = allNodes.Union(Enumerable.Range(0, evoConfig.InputNodeCount + 1)).ToList(); List<int> availableOutputNodeList = allNodes.Union(Enumerable.Range(evoConfig.InputNodeCount + 1, evoConfig.OutputNodeCount)).ToList(); // Select a Node int n1 = (biasOnly) ? evoConfig.InputNodeCount : availableInputNodeList[rng.Next(availableInputNodeList.Count())]; // Remove this node from the list if (availableOutputNodeList.Contains(n1)) availableOutputNodeList.Remove(n1); // Select a Node After int n2 = availableOutputNodeList[rng.Next(availableOutputNodeList.Count())]; // Create new gene Gene newGene = new Gene(evoConfig, n1, n2); newGene.ConnectionWeight = 2 - evoConfig.rng.NextDouble() * 4; // Insert new gene Genes.Add(newGene); }