private void InitInnovation(Genome basicGenome) { if (basicGenome.ConnectionGenes.Count > 0) { Innovation.SetCurrentID(basicGenome.ConnectionGenes[basicGenome.ConnectionGenes.Count - 1].Innovation); } else { Innovation.SetCurrentID(0); } }
// Mutation that creates new node in the genome. public void AddNodeMutation(List <Innovation> innovations) { if (innovations == null) { throw new ArgumentNullException(nameof(innovations)); } // If there are no genes at all, return if (connectionGenes.Count == 0) { return; } bool found = false; int connectionIndex = -1; found = this.FindConnectionGeneToSplit(out connectionIndex); // We haven't found any proper gene to split, so exit if (!found) { return; } ConnectionGene oldConnection = this.connectionGenes[connectionIndex]; oldConnection.IsEnabled = false; // Check if this is new innovation, or whether it already exists somewhere in the population bool innovationFound = false; Node newNode = null; ConnectionGene newGene1 = null; ConnectionGene newGene2 = null; foreach (Innovation innov in innovations) { if (innov.InnovationType == Innovation.EInnovationType.NEWNODE && innov.InNode.ID == oldConnection.InNodeGene.ID && innov.OutNode.ID == oldConnection.OutNodeGene.ID && oldConnection.Innovation == innov.OldID) { innovationFound = true; newNode = new Node(Node.ENodeType.HIDDEN, innov.NewNode.ID); newGene1 = new ConnectionGene(oldConnection.InNodeGene, newNode, oldConnection.IsRecurrent, 1.0f, true, innov.ID); newGene2 = new ConnectionGene(newNode, oldConnection.OutNodeGene, false, oldConnection.Weight, true, innov.ID2); break; } } // Create new hidden node between old nodes and link it with the network if (!innovationFound) { newNode = new Node(Node.ENodeType.HIDDEN, this.nodes.Count + 1); int id1 = Innovation.GetNextID(); int id2 = Innovation.GetNextID(); Innovation newInnov = new Innovation(Innovation.EInnovationType.NEWNODE, oldConnection.InNodeGene, oldConnection.OutNodeGene, newNode, id1, id2, 0.0f, oldConnection.Innovation); innovations.Add(newInnov); newGene1 = new ConnectionGene(oldConnection.InNodeGene, newNode, oldConnection.IsRecurrent, 1.0f, true, id1); newGene2 = new ConnectionGene(newNode, oldConnection.OutNodeGene, false, oldConnection.Weight, true, id2); } this.AddNode(newNode); this.AddConnectionGene(newGene1); this.AddConnectionGene(newGene2); this.phenotypeChanged = true; }
// Mutation that creates new connection between 2 nodes. public void AddConnectionMutation(List <Innovation> innovations) { if (innovations == null) { throw new ArgumentNullException(nameof(innovations)); } // Find first non-sensor node, so the target is never a sensor int minTargetNode = this.FindFirstNonInputNode(); bool doRecurrency = this.random.NextDouble() < this.ParentSimulation.Parameters.RecurrencyProbability; bool recurFlag = false; bool found = false; Node node1 = null, node2 = null; if (doRecurrency) { int counter = 0; while (counter++ < maxTries && !found) { bool recurrentLoop = this.random.NextDouble() > 0.5; int startNode = this.random.Next(0, this.nodes.Count); int targetNode = recurrentLoop ? startNode : this.random.Next(minTargetNode, this.nodes.Count); // Check if connection exists between the nodes int i = 0; node1 = this.nodes[startNode]; node2 = this.nodes[targetNode]; for (i = 0; i < this.connectionGenes.Count; ++i) { if ((node2.NodeType == Node.ENodeType.SENSOR || node2.NodeType == Node.ENodeType.BIAS) || (connectionGenes[i].InNodeGene.ID == node1.ID && connectionGenes[i].OutNodeGene.ID == node2.ID && connectionGenes[i].IsRecurrent)) { break; } } if (i == this.connectionGenes.Count) { recurFlag = this.IsRecurrentConnectioBetweenNodes(node1, node2); if (!recurFlag) { continue; } else { found = true; } } } } else { int counter = 0; while (counter++ < maxTries && !found) { int startNode = this.random.Next(0, this.nodes.Count); int targetNode = this.random.Next(minTargetNode, this.nodes.Count); if (startNode != targetNode) { // Check if connection exists between the nodes int i = 0; node1 = this.nodes[startNode]; // Don't allow recurrencies for now if (node1.NodeType == Node.ENodeType.OUTPUT) { continue; } node2 = this.nodes[targetNode]; for (i = 0; i < this.connectionGenes.Count; ++i) { if (connectionGenes[i].InNodeGene.ID == node1.ID && connectionGenes[i].OutNodeGene.ID == node2.ID && !connectionGenes[i].IsRecurrent) { break; } } if (i == this.connectionGenes.Count) { recurFlag = this.IsRecurrentConnectioBetweenNodes(node1, node2); if (recurFlag) { continue; } else { found = true; } } } } } // Check if this is new innovation, or if it already existed somewhere in the population if (found) { if (doRecurrency) { recurFlag = true; } bool innovationFound = false; ConnectionGene newGene = null; foreach (Innovation innov in innovations) { if (innov.InnovationType == Innovation.EInnovationType.NEWLINK && innov.InNode.ID == node1.ID && innov.OutNode.ID == node2.ID) { innovationFound = true; newGene = new ConnectionGene(innov.InNode, innov.OutNode, recurFlag, innov.Weight, true, innov.ID); break; } } // This is completely new innovation if (!innovationFound) { float newRandomWeight = (float)(this.random.NextDouble() * 2.0f - 1.0f); Innovation newInnov = new Innovation(Innovation.EInnovationType.NEWLINK, node1, node2, null, Innovation.GetNextID(), 0, newRandomWeight, 0); innovations.Add(newInnov); newGene = new ConnectionGene(node1, node2, recurFlag, newRandomWeight, true, newInnov.ID); } this.AddConnectionGene(newGene); this.phenotypeChanged = true; } }