/// <summary> /// Adds Connection (Structural Mutation) to Genome from Nodes /// </summary> /// <param name="nodeFrom">From-Node for Connection</param> /// <param name="nodeTo">To-Node for Connection</param> internal void MutateAddConnection(NodeGene nodeFrom, NodeGene nodeTo) { if (!nodeFrom.IsValid) { throw new ArgumentException("NodeFrom is Invalid", "nodeFrom"); } if (!nodeTo.IsValid) { throw new ArgumentException("NodeTo is Invalid", "nodeTo"); } if (nodeFrom.Equals(nodeTo)) { throw new ArgumentException("Cannot create Connection with a single Node"); } if (!Nodes.ContainsKey(nodeFrom.Innovation)) { throw new ArgumentException("Node does not exist in Genome", "nodeFrom"); } if (!Nodes.ContainsKey(nodeTo.Innovation)) { throw new ArgumentException("Node does not exist in Genome", "nodeTo"); } if (nodeFrom.Type == NodeType.OUTPUT || nodeTo.Type == NodeType.INPUT) { throw new InvalidOperationException($"Invalid NodeTypes for Connection. Type NodeFrom: {nodeFrom.Type} Type NodeTo: {nodeTo.Type}"); } // TODO: Check if Connection does not exist already in Genome AddConnection(MutationFactory.GetConnection(nodeFrom, nodeTo)); }
/// <summary> /// Adds random connection (Structural Mutation) to Genome /// </summary> internal void MutateAddRandomConnection() { if (Nodes.Count < 2) { throw new InvalidOperationException("Not enough Existing Nodes"); } // Separate out the Nodes by Type List <NodeGene> inputNodes = new List <NodeGene>(); List <NodeGene> hiddenNodes = new List <NodeGene>(); List <NodeGene> outputNodes = new List <NodeGene>(); foreach (NodeGene node in Nodes.Values) { switch (node.Type) { case NodeType.INPUT: inputNodes.Add(node); break; case NodeType.HIDDEN: hiddenNodes.Add(node); break; case NodeType.OUTPUT: outputNodes.Add(node); break; default: break; } } // Add hiddenNodes to both lists to create the choice-lists inputNodes.AddRange(hiddenNodes); outputNodes.AddRange(hiddenNodes); // Find 2 nodes in these 2 lists which are NOT connected NodeGene inputNode = inputNodes[Functions.GetRandomNumber(0, inputNodes.Count)]; // Pick random inputNode int attempts = 0; while (attempts < MaxFindAttempts) // TODO: Improve this { attempts++; NodeGene outputNode = outputNodes[Functions.GetRandomNumber(0, outputNodes.Count)]; if (inputNode.Equals(outputNode)) // Same (hidden) node, can't connect to self { continue; } bool foundConnection = false; foreach (ConnectionGene conn in Connections.Values) { if (conn.HasNode(inputNode) && conn.HasNode(outputNode)) { foundConnection = true; break; // Connection Exists } } if (foundConnection) { continue; // failed to find valid pair } // InputNode != OutputNode and !(I->O) && !(O->I) AddConnection(MutationFactory.GetConnection(inputNode, outputNode)); return; } Console.WriteLine("Failed to add Connection"); }