public override bool Equals(object obj) { if (obj == null) { return(false); } if (obj.GetType() != typeof(ConnectionEndpointsStruct)) { return(false); } ConnectionEndpointsStruct ces = (ConnectionEndpointsStruct)obj; return((sourceNeuronId == ces.sourceNeuronId) && (targetNeuronId == ces.targetNeuronId)); }
/// <summary> /// Adds a connection to the list that will eventually be copied into a child of this genome during sexual reproduction. /// A helper function that is only called by CreateOffspring_Sexual_ProcessCorrelationItem(). /// </summary> /// <param name="connectionGene">Specifies the connection to add to this genome.</param> /// <param name="overwriteExisting">If there is already a connection from the same source to the same target, /// that connection is replaced when overwriteExisting is true and remains (no change is made) when overwriteExisting is false.</param> private void CreateOffspring_Sexual_AddGene(ConnectionGene connectionGene, bool overwriteExisting) { ConnectionEndpointsStruct connectionKey = new ConnectionEndpointsStruct( connectionGene.SourceNeuronId, connectionGene.TargetNeuronId); // Check if a matching gene has already been added. object oIdx = newConnectionGeneTable[connectionKey]; if(oIdx==null) { // No matching gene has been added. // Register this new gene with the newConnectionGeneTable - store its index within newConnectionGeneList. newConnectionGeneTable[connectionKey] = newConnectionGeneList.Count; // Add the gene to the list. newConnectionGeneList.Add(connectionGene); } else if(overwriteExisting) { // Overwrite the existing matching gene with this one. In fact only the weight value differs between two // matching connection genes, so just overwrite the existing genes weight value. // Remember that we stored the gene's index in newConnectionGeneTable. So use it here. newConnectionGeneList[(int)oIdx].Weight = connectionGene.Weight; } }
private void RemoveSimpleNeuron(uint neuronId, EvolutionAlgorithm ea) { // Create new connections that connect all of the incoming and outgoing neurons // that currently exist for the simple neuron. NeuronConnectionLookup lookup = (NeuronConnectionLookup)neuronConnectionLookupTable[neuronId]; foreach(ConnectionGene incomingConnection in lookup.incomingList) { foreach(ConnectionGene outgoingConnection in lookup.outgoingList) { if(TestForExistingConnection(incomingConnection.SourceNeuronId, outgoingConnection.TargetNeuronId)) { // Connection already exists. continue; } // Test for matching connection within NewConnectionGeneTable. ConnectionEndpointsStruct connectionKey = new ConnectionEndpointsStruct(incomingConnection.SourceNeuronId, outgoingConnection.TargetNeuronId); ConnectionGene existingConnection = (ConnectionGene)ea.NewConnectionGeneTable[connectionKey]; ConnectionGene newConnectionGene; if(existingConnection==null) { // No matching connection found. Create a connection with a new ID. newConnectionGene = new ConnectionGene(ea.NextInnovationId, incomingConnection.SourceNeuronId, outgoingConnection.TargetNeuronId, (Utilities.NextDouble() * ea.NeatParameters.connectionWeightRange) - ea.NeatParameters.connectionWeightRange/2.0); // Register the new ID with NewConnectionGeneTable. ea.NewConnectionGeneTable.Add(connectionKey, newConnectionGene); // Add the new gene to the genome. connectionGeneList.Add(newConnectionGene); } else { // Matching connection found. Re-use its ID. newConnectionGene = new ConnectionGene(existingConnection.InnovationId, incomingConnection.SourceNeuronId, outgoingConnection.TargetNeuronId, (Utilities.NextDouble() * ea.NeatParameters.connectionWeightRange) - ea.NeatParameters.connectionWeightRange/2.0); // Add the new gene to the genome. Use InsertIntoPosition() to ensure we don't break the sort // order of the connection genes. connectionGeneList.InsertIntoPosition(newConnectionGene); } } } // Delete the old connections. foreach(ConnectionGene incomingConnection in lookup.incomingList) connectionGeneList.Remove(incomingConnection); foreach(ConnectionGene outgoingConnection in lookup.outgoingList) { // Filter out recurrent connections - they will have already been // deleted in the loop through 'lookup.incomingList'. if(outgoingConnection.TargetNeuronId != neuronId) connectionGeneList.Remove(outgoingConnection); } // Delete the simple neuron - it no longer has any connections to or from it. neuronGeneList.Remove(neuronId); }
private void Mutate_AddConnection(EvolutionAlgorithm ea) { // We are always guaranteed to have enough neurons to form connections - because the input/output neurons are // fixed. Any domain that doesn't require input/outputs is a bit nonsensical! // Make a fixed number of attempts at finding a suitable connection to add. if(neuronGeneList.Count>1) { // At least 2 neurons, so we have a chance at creating a connection. for(int attempts=0; attempts<5; attempts++) { // Select candidate source and target neurons. Any neuron can be used as the source. Input neurons // should not be used as a target int srcNeuronIdx; int tgtNeuronIdx; /* Here's some code for adding connections that attempts to avoid any recursive conenctions * within a network by only linking to neurons with innovation id's greater than the source neuron. * Unfortunately this doesn't work because new neurons with large innovations ID's are inserted * randomly through a network's topology! Hence this code remains here in readyness to be resurrected * as part of some future work to support feedforward nets. // if(ea.NeatParameters.feedForwardOnly) // { // /* We can ensure that all networks are feedforward only by only adding feedforward connections here. // * Feed forward connections fall into one of the following categories. All references to indexes // * are indexes within this genome's neuronGeneList: // * 1) Source neuron is an input or hidden node, target is an output node. // * 2) Source is an input or hidden node, target is a hidden node with an index greater than the source node's index. // * 3) Source is an output node, target is an output node with an index greater than the source node's index. // * // * These rules are easier to understand if you understand how the different types if neuron are arranged within // * the neuronGeneList array. Neurons are arranged in the following order: // * // * 1) A single bias neuron is always first. // * 2) Experiment specific input neurons. // * 3) Output neurons. // * 4) Hidden neurons. // * // * The quantity and innovationID of all neurons within the first 3 categories remains fixed throughout the life // * of an experiment, hence we always know where to find the bias, input and output nodes. The number of hidden nodes // * can vary as ne nodes are created, pruned away or perhaps dropped during crossover, however they are always arranged // * newest to oldest, or in other words sorted by innovation idea, lowest ID first. // * // * If output neurons were at the end of the list with hidden nodes in the middle then generating feedforward // * connections would be as easy as selecting a target neuron with a higher index than the source neuron. However, that // * type of arrangement is not conducive to the operation of other routines, hence this routine is a little bit more // * complicated as a result. // */ // // // Ok, for a source neuron we can pick any neuron except the last output neuron. // int neuronIdxCount = neuronGeneList.Count; // int neuronIdxBound = neuronIdxCount-1; // // // Generate count-1 possibilities and avoid the last output neuron's idx. // srcNeuronIdx = (int)Math.Floor(Utilities.NextDouble() * neuronIdxBound); // if(srcNeuronIdx>inputBiasOutputNeuronCountMinus2) srcNeuronIdx++; // // // // Now generate a target idx depending on what type of neuron srcNeuronIdx is pointing to. // if(srcNeuronIdx<inputAndBiasNeuronCount) // { // Source is a bias or input neuron. Target can be any output or hidden neuron. // tgtNeuronIdx = inputAndBiasNeuronCount + (int)Math.Floor(Utilities.NextDouble() * (neuronIdxCount-inputAndBiasNeuronCount)); // } // else if(srcNeuronIdx<inputBiasOutputNeuronCount) // { // Source is an output neuron, but not the last output neuron. Target can be any output neuron with an index // // greater than srcNeuronIdx. // tgtNeuronIdx = (inputAndBiasNeuronCount+1) + (int)Math.Floor(Utilities.NextDouble() * ((inputBiasOutputNeuronCount-1)-srcNeuronIdx)); // } // else // { // Source is a hidden neuron. Target can be any hidden neuron after srcNeuronIdx or any output neuron. // tgtNeuronIdx = (int)Math.Floor(Utilities.NextDouble() * ((neuronIdxBound-srcNeuronIdx)+outputNeuronCount)); // // if(tgtNeuronIdx<outputNeuronCount) // { // Map to an output neuron idx. // tgtNeuronIdx += inputAndBiasNeuronCount; // } // else // { // // Map to one of the hidden neurons after srcNeuronIdx. // tgtNeuronIdx = (tgtNeuronIdx-outputNeuronCount)+srcNeuronIdx+1; // } // } // } // // Source neuron can by any neuron. Target neuron is any neuron except input neurons. // srcNeuronIdx = (int)Math.Floor(Utilities.NextDouble() * neuronGeneList.Count); // tgtNeuronIdx = inputAndBiasNeuronCount + (int)Math.Floor(Utilities.NextDouble() * (neuronGeneList.Count-inputAndBiasNeuronCount)); // // NeuronGene sourceNeuron = neuronGeneList[srcNeuronIdx]; // NeuronGene targetNeuron = neuronGeneList[tgtNeuronIdx]; // Find all potential inputs, or quit if there are not enough. // Neurons cannot be inputs if they are dummy input nodes of a module. NeuronGeneList potentialInputs = new NeuronGeneList(); foreach (NeuronGene n in neuronGeneList) { if (!(n.ActivationFunction is ModuleInputNeuron)) { potentialInputs.Add(n); } } if (potentialInputs.Count < 1) return; // Find all potential outputs, or quit if there are not enough. // Neurons cannot be outputs if they are dummy input or output nodes of a module, or network input or bias nodes. NeuronGeneList potentialOutputs = new NeuronGeneList(); foreach (NeuronGene n in neuronGeneList) { if (n.NeuronType != NeuronType.Bias && n.NeuronType != NeuronType.Input && !(n.ActivationFunction is ModuleInputNeuron) && !(n.ActivationFunction is ModuleOutputNeuron)) { potentialOutputs.Add(n); } } if (potentialOutputs.Count < 1) return; NeuronGene sourceNeuron = potentialInputs[Utilities.Next(potentialInputs.Count)]; NeuronGene targetNeuron = potentialOutputs[Utilities.Next(potentialOutputs.Count)]; // Check if a connection already exists between these two neurons. uint sourceId = sourceNeuron.InnovationId; uint targetId = targetNeuron.InnovationId; if(!TestForExistingConnection(sourceId, targetId)) { // Check if a matching mutation has already occured on another genome. // If so then re-use the connection ID. ConnectionEndpointsStruct connectionKey = new ConnectionEndpointsStruct(sourceId, targetId); ConnectionGene existingConnection = (ConnectionGene)ea.NewConnectionGeneTable[connectionKey]; ConnectionGene newConnectionGene; if(existingConnection==null) { // Create a new connection with a new ID and add it to the Genome. newConnectionGene = new ConnectionGene(ea.NextInnovationId, sourceId, targetId, (Utilities.NextDouble() * ea.NeatParameters.connectionWeightRange/4.0) - ea.NeatParameters.connectionWeightRange/8.0); // Register the new connection with NewConnectionGeneTable. ea.NewConnectionGeneTable.Add(connectionKey, newConnectionGene); // Add the new gene to this genome. We have a new ID so we can safely append the gene to the end // of the list without risk of breaking the innovation ID order. connectionGeneList.Add(newConnectionGene); } else { // Create a new connection, re-using the ID from existingConnection, and add it to the Genome. newConnectionGene = new ConnectionGene(existingConnection.InnovationId, sourceId, targetId, (Utilities.NextDouble() * ea.NeatParameters.connectionWeightRange/4.0) - ea.NeatParameters.connectionWeightRange/8.0); // Add the new gene to this genome. We are re-using an ID so we must ensure the connection gene is // inserted into the correct position (sorted by innovation ID). connectionGeneList.InsertIntoPosition(newConnectionGene); } return; } } } // We couldn't find a valid connection to create. Instead of doing nothing lets perform connection // weight mutation. Mutate_ConnectionWeights(ea); }
private void Mutate_AddModule(EvolutionAlgorithm ea) { // Find all potential inputs, or quit if there are not enough. // Neurons cannot be inputs if they are dummy input nodes created for another module. NeuronGeneList potentialInputs = new NeuronGeneList(); foreach (NeuronGene n in neuronGeneList) { if (!(n.ActivationFunction is ModuleInputNeuron)) { potentialInputs.Add(n); } } if (potentialInputs.Count < 1) return; // Find all potential outputs, or quit if there are not enough. // Neurons cannot be outputs if they are dummy input or output nodes created for another module, or network input or bias nodes. NeuronGeneList potentialOutputs = new NeuronGeneList(); foreach (NeuronGene n in neuronGeneList) { if (n.NeuronType != NeuronType.Bias && n.NeuronType != NeuronType.Input && !(n.ActivationFunction is ModuleInputNeuron) && !(n.ActivationFunction is ModuleOutputNeuron)) { potentialOutputs.Add(n); } } if (potentialOutputs.Count < 1) return; // Pick a new function for the new module. IModule func = ModuleFactory.GetRandom(); // Choose inputs uniformly at random, with replacement. // Create dummy neurons to represent the module's inputs. // Create connections between the input nodes and the dummy neurons. IActivationFunction inputFunction = ActivationFunctionFactory.GetActivationFunction("ModuleInputNeuron"); List<uint> inputDummies = new List<uint>(func.InputCount); for (int i = 0; i < func.InputCount; i++) { NeuronGene newNeuronGene = new NeuronGene(ea.NextInnovationId, NeuronType.Hidden, inputFunction); neuronGeneList.Add(newNeuronGene); uint sourceId = potentialInputs[Utilities.Next(potentialInputs.Count)].InnovationId; uint targetId = newNeuronGene.InnovationId; inputDummies.Add(targetId); // Create a new connection with a new ID and add it to the Genome. ConnectionGene newConnectionGene = new ConnectionGene(ea.NextInnovationId, sourceId, targetId, (Utilities.NextDouble() * ea.NeatParameters.connectionWeightRange) - ea.NeatParameters.connectionWeightRange / 2.0); // Register the new connection with NewConnectionGeneTable. ConnectionEndpointsStruct connectionKey = new ConnectionEndpointsStruct(sourceId, targetId); ea.NewConnectionGeneTable.Add(connectionKey, newConnectionGene); // Add the new gene to this genome. We have a new ID so we can safely append the gene to the end // of the list without risk of breaking the innovation ID order. connectionGeneList.Add(newConnectionGene); } // Choose outputs uniformly at random, with replacement. // Create dummy neurons to represent the module's outputs. // Create connections between the output nodes and the dummy neurons. IActivationFunction outputFunction = ActivationFunctionFactory.GetActivationFunction("ModuleOutputNeuron"); List<uint> outputDummies = new List<uint>(func.OutputCount); for (int i = 0; i < func.OutputCount; i++) { NeuronGene newNeuronGene = new NeuronGene(ea.NextInnovationId, NeuronType.Hidden, outputFunction); neuronGeneList.Add(newNeuronGene); uint sourceId = newNeuronGene.InnovationId; uint targetId = potentialOutputs[Utilities.Next(potentialOutputs.Count)].InnovationId; outputDummies.Add(sourceId); // Create a new connection with a new ID and add it to the Genome. ConnectionGene newConnectionGene = new ConnectionGene(ea.NextInnovationId, sourceId, targetId, (Utilities.NextDouble() * ea.NeatParameters.connectionWeightRange) - ea.NeatParameters.connectionWeightRange / 2.0); // Register the new connection with NewConnectionGeneTable. ConnectionEndpointsStruct connectionKey = new ConnectionEndpointsStruct(sourceId, targetId); ea.NewConnectionGeneTable.Add(connectionKey, newConnectionGene); // Add the new gene to this genome. We have a new ID so we can safely append the gene to the end // of the list without risk of breaking the innovation ID order. connectionGeneList.Add(newConnectionGene); } // Pick a new ID for the new module and create it. // Modules do not participate in history comparisons, so we will always create a new innovation ID. // We can change this here if it becomes a problem. ModuleGene newModule = new ModuleGene(ea.NextInnovationId, func, inputDummies, outputDummies); moduleGeneList.Add(newModule); }
/// <summary> /// Search for connections with the same end-points throughout the whole population and /// ensure that like connections have the same innovation ID. /// </summary> private void MatchConnectionIds() { Hashtable connectionIdTable = new Hashtable(); int genomeBound=pop.GenomeList.Count; for(int genomeIdx=0; genomeIdx<genomeBound; genomeIdx++) { NeatGenome.NeatGenome genome = (NeatGenome.NeatGenome)pop.GenomeList[genomeIdx]; int connectionGeneBound = genome.ConnectionGeneList.Count; for(int connectionGeneIdx=0; connectionGeneIdx<connectionGeneBound; connectionGeneIdx++) { ConnectionGene connectionGene = genome.ConnectionGeneList[connectionGeneIdx]; ConnectionEndpointsStruct ces = new ConnectionEndpointsStruct(); ces.sourceNeuronId = connectionGene.SourceNeuronId; ces.targetNeuronId = connectionGene.TargetNeuronId; Object existingConnectionIdObject = connectionIdTable[ces]; if(existingConnectionIdObject==null) { // No connection withthe same end-points has been registered yet, so // add it to the table. connectionIdTable.Add(ces, connectionGene.InnovationId); } else { // This connection is already registered. Give our latest connection // the same innovation ID as the one in the table. connectionGene.InnovationId = (uint)existingConnectionIdObject; } } // The connection genes in this genome may now be out of order. Therefore we must ensure // they are sorted before we continue. genome.ConnectionGeneList.SortByInnovationId(); } }
private void RemoveSimpleNeuron(long neuronId, NeatParameters neatParameters, IdGenerator idGen, Hashtable NewConnectionGeneTable) { WINManager win = WINManager.SharedWIN; //WINNode node; WINConnection connection; // Create new connections that connect all of the incoming and outgoing neurons // that currently exist for the simple neuron. NeuronConnectionLookup lookup = (NeuronConnectionLookup)neuronConnectionLookupTable[neuronId]; foreach(ConnectionGene incomingConnection in lookup.incomingList) { foreach(ConnectionGene outgoingConnection in lookup.outgoingList) { if(TestForExistingConnection(incomingConnection.SourceNeuronId, outgoingConnection.TargetNeuronId)) { // Connection already exists. continue; } // Test for matching connection within NewConnectionGeneTable. ConnectionEndpointsStruct connectionKey = new ConnectionEndpointsStruct(incomingConnection.SourceNeuronId, outgoingConnection.TargetNeuronId); ConnectionGene existingConnection = (ConnectionGene)NewConnectionGeneTable[connectionKey]; ConnectionGene newConnectionGene; if(existingConnection==null) { // No matching connection found. Create a connection with a new ID. //create our newest conncetion, noting the source,target and weight connection = win.createWINConnection( WINConnection.ConnectionWithProperties(incomingConnection.SourceNeuronId, outgoingConnection.TargetNeuronId), idGen); // Create a new connection with a new ID and add it to the Genome. newConnectionGene = new ConnectionGene(connection.UniqueID, connection.SourceID, connection.TargetID, (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0 ); //newConnectionGene = new ConnectionGene(idGen.NextInnovationId, // incomingConnection.SourceNeuronId, // outgoingConnection.TargetNeuronId, // (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange/2.0); // Register the new ID with NewConnectionGeneTable. NewConnectionGeneTable.Add(connectionKey, newConnectionGene); // Add the new gene to the genome. connectionGeneList.Add(newConnectionGene); } else { //WIN should acknowledge change in individual here // Matching connection found. Re-use its ID. newConnectionGene = new ConnectionGene(existingConnection.InnovationId, incomingConnection.SourceNeuronId, outgoingConnection.TargetNeuronId, (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange/2.0); // Add the new gene to the genome. Use InsertIntoPosition() to ensure we don't break the sort // order of the connection genes. connectionGeneList.InsertIntoPosition(newConnectionGene); } } } // Delete the old connections. foreach(ConnectionGene incomingConnection in lookup.incomingList) connectionGeneList.Remove(incomingConnection); foreach(ConnectionGene outgoingConnection in lookup.outgoingList) { // Filter out recurrent connections - they will have already been // deleted in the loop through 'lookup.incomingList'. if(outgoingConnection.TargetNeuronId != neuronId) connectionGeneList.Remove(outgoingConnection); } // Delete the simple neuron - it no longer has any connections to or from it. neuronGeneList.Remove(neuronId); }
private void Mutate_AddModule(NeatParameters neatParameters, IdGenerator idGen, Hashtable NewConnectionGeneTable) { // Find all potential inputs, or quit if there are not enough. // Neurons cannot be inputs if they are dummy input nodes created for another module. NeuronGeneList potentialInputs = new NeuronGeneList(); foreach (NeuronGene n in neuronGeneList) { if (!(n.ActivationFunction is ModuleInputNeuron)) { potentialInputs.Add(n); } } if (potentialInputs.Count < 1) return; // Find all potential outputs, or quit if there are not enough. // Neurons cannot be outputs if they are dummy input or output nodes created for another module, or network input or bias nodes. NeuronGeneList potentialOutputs = new NeuronGeneList(); foreach (NeuronGene n in neuronGeneList) { if (n.NeuronType != NeuronType.Bias && n.NeuronType != NeuronType.Input && !(n.ActivationFunction is ModuleInputNeuron) && !(n.ActivationFunction is ModuleOutputNeuron)) { potentialOutputs.Add(n); } } if (potentialOutputs.Count < 1) return; // Pick a new function for the new module. IModule func = ModuleFactory.GetRandom(); WINManager win = WINManager.SharedWIN; WINNode node; WINConnection connection; // Choose inputs uniformly at random, with replacement. // Create dummy neurons to represent the module's inputs. // Create connections between the input nodes and the dummy neurons. IActivationFunction inputFunction = ActivationFunctionFactory.GetActivationFunction("ModuleInputNeuron"); List<long> inputDummies = new List<long>(func.InputCount); for (int i = 0; i < func.InputCount; i++) { //we are calling nextinnovationID, this is the place for WIN! //in reality, win should know the activation function as well, but that's not currently implemented //here we create a new node, and two new connections //we don't send in a genomeID here, so we get it set for us! //do we need to inform it of the activation function? I think so? node = win.createWINNode(new PropertyObject() { { WINNode.SNodeString, NeuronType.Hidden.ToString()}}); NeuronGene newNeuronGene = new NeuronGene(node.UniqueID, NeuronType.Hidden, inputFunction); neuronGeneList.Add(newNeuronGene); long sourceId = potentialInputs[Utilities.Next(potentialInputs.Count)].InnovationId; long targetId = newNeuronGene.InnovationId; inputDummies.Add(targetId); //aha! we must call the innovationID again, we check against win //we don't send in any uniqueIDs so they are generated for us, and we update our idGen object connection = win.createWINConnection( WINConnection.ConnectionWithProperties(sourceId, targetId), idGen); // Create a new connection with a new ID and add it to the Genome. ConnectionGene newConnectionGene = new ConnectionGene(connection.UniqueID, connection.SourceID, connection.TargetID, (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0 ); // Register the new connection with NewConnectionGeneTable. ConnectionEndpointsStruct connectionKey = new ConnectionEndpointsStruct(sourceId, targetId); NewConnectionGeneTable.Add(connectionKey, newConnectionGene); // Add the new gene to this genome. We have a new ID so we can safely append the gene to the end // of the list without risk of breaking the innovation ID order. connectionGeneList.Add(newConnectionGene); } // Choose outputs uniformly at random, with replacement. // Create dummy neurons to represent the module's outputs. // Create connections between the output nodes and the dummy neurons. IActivationFunction outputFunction = ActivationFunctionFactory.GetActivationFunction("ModuleOutputNeuron"); List<long> outputDummies = new List<long>(func.OutputCount); for (int i = 0; i < func.OutputCount; i++) { node = win.createWINNode(new PropertyObject() { { WINNode.SNodeString, NeuronType.Hidden.ToString() } }); NeuronGene newNeuronGene = new NeuronGene(node.UniqueID, NeuronType.Hidden, outputFunction); neuronGeneList.Add(newNeuronGene); long sourceId = newNeuronGene.InnovationId; long targetId = potentialOutputs[Utilities.Next(potentialOutputs.Count)].InnovationId; outputDummies.Add(sourceId); connection = win.createWINConnection( WINConnection.ConnectionWithProperties(sourceId, targetId), idGen); // Create a new connection with a new ID and add it to the Genome. ConnectionGene newConnectionGene = new ConnectionGene(connection.UniqueID, connection.SourceID, connection.TargetID, (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0 ); //new ConnectionGene(idGen.NextInnovationId, sourceId, targetId, //(Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0); // Register the new connection with NewConnectionGeneTable. ConnectionEndpointsStruct connectionKey = new ConnectionEndpointsStruct(sourceId, targetId); NewConnectionGeneTable.Add(connectionKey, newConnectionGene); // Add the new gene to this genome. We have a new ID so we can safely append the gene to the end // of the list without risk of breaking the innovation ID order. connectionGeneList.Add(newConnectionGene); } // Pick a new ID for the new module and create it. // Modules do not participate in history comparisons, so we will always create a new innovation ID. // We can change this here if it becomes a problem. //TODO: Paul check win conditions here //this is confusing from a WIN perspective, I don't know if I'm going to support modules //I can create a generic NextInnovationID object, but don't know if it's worth it ModuleGene newModule = new ModuleGene(idGen.NextInnovationId, func, inputDummies, outputDummies); moduleGeneList.Add(newModule); }