public static NeatGenome <double> CreateNeatGenome2( INeatGenomeBuilder <double> genomeBuilder) { var connGenes = new ConnectionGenes <double>(12); connGenes[0] = (0, 3, 0.3); connGenes[1] = (0, 4, 0.4); connGenes[2] = (0, 5, 0.5); connGenes[3] = (3, 6, 3.6); connGenes[4] = (4, 7, 4.7); connGenes[5] = (5, 8, 5.8); connGenes[6] = (6, 9, 6.9); connGenes[7] = (7, 10, 7.1); connGenes[8] = (8, 11, 8.11); connGenes[9] = (9, 1, 9.1); connGenes[10] = (10, 1, 10.1); connGenes[11] = (11, 1, 11.1); var genome = genomeBuilder.Create(1, 0, connGenes); return(genome); }
private NeatGenome <T> LoadInner(StreamReader sr) { // Reset line counter. _lineIdx = 0; // Read node counts. int inputCount = ReadInt32Line(); int outputCount = ReadInt32Line(); ReadEndOfSection(); ValidateNodeCounts(inputCount, outputCount); // Read connections. ReadConnections(out DirectedConnection[] connArr, out T[] weightArr); // Read activation function(s). // Note. For a NeatGenome we expect a single line specifying a single activation function with ID 0, // and a function code that specifies the function. Additional lines in the section are ignored. ReadActivationFunctions(); // Read activation function(s). ValidateActivationFunctions(); // Create a genome object and return. var connGenes = new ConnectionGenes <T>(connArr, weightArr); return(_genomeBuilder.Create(_genomeId++, 0, connGenes)); }
/// <summary> /// Create a new child genome from a given parent genome. /// </summary> /// <param name="parent">The parent genome.</param> /// <param name="rng">Random source.</param> /// <returns>A new child genome.</returns> public NeatGenome <T> CreateChildGenome(NeatGenome <T> parent, IRandomSource rng) { // Clone the parent's connection weight array. var weightArr = (T[])parent.ConnectionGenes._weightArr.Clone(); // Apply mutation to the connection weights. _weightMutationScheme.MutateWeights(weightArr, rng); // Create the child genome's ConnectionGenes object. // Note. The parent genome's connection arrays are re-used; these remain unchanged because we are mutating // connection *weights* only, so we can avoid the cost of cloning these arrays. var connGenes = new ConnectionGenes <T>( parent.ConnectionGenes._connArr, weightArr); // Create and return a new genome. // Note. The parent's ConnectionIndexArray and HiddenNodeIdArray can be re-used here because the new genome // has the same set of connections (same neural net structure). return(_genomeBuilder.Create( _genomeIdSeq.Next(), _generationSeq.Peek, connGenes, parent.HiddenNodeIdArray, parent.NodeIndexByIdMap, parent.DirectedGraph, parent.ConnectionIndexMap)); }
private NeatGenome <T> CreateGenomeInner(NeatGenome <T> parent1, NeatGenome <T> parent2) { // Randomly select one parent as being the primary parent. if (_rng.NextBool()) { VariableUtils.Swap(ref parent1, ref parent2); } // Enumerate over the connection genes in both parents. foreach (var geneIndexPair in EnumerateParentGenes(parent1.ConnectionGenes, parent2.ConnectionGenes)) { // Create a connection gene based on the current position in both parents. ConnectionGene <T>?connGene = CreateConnectionGene( parent1.ConnectionGenes, parent2.ConnectionGenes, geneIndexPair.Item1, geneIndexPair.Item2, out bool isSecondaryGene); if (connGene.HasValue) { // Attempt to add the gene to the child genome we are building. _builder.TryAddGene(connGene.Value, isSecondaryGene); } } // Convert the genes to the structure required by NeatGenome. var connGenes = _builder.ToConnectionGenes(); // Create and return a new genome. return(_genomeBuilder.Create( _genomeIdSeq.Next(), _generationSeq.Peek, connGenes)); }
private NeatGenome <T> CreateGenomeInner( NeatGenome <T> parent1, NeatGenome <T> parent2, IRandomSource rng) { // Resolve a flag that determines if *all* disjoint genes from the secondary parent will be included in the child genome, or not. // This approach is from SharpNEAT v2.x and is preserved to act as baseline in v4.x, but better strategies may exist. bool includeSecondaryParentGene = DiscreteDistribution.SampleBernoulli(rng, _secondaryParentGeneProbability); // Enumerate over the connection genes in both parents. foreach (var geneIndexPair in EnumerateParentGenes(parent1.ConnectionGenes, parent2.ConnectionGenes)) { // Create a connection gene based on the current position in both parents. ConnectionGene <T>?connGene = CreateConnectionGene( parent1.ConnectionGenes, parent2.ConnectionGenes, geneIndexPair.Item1, geneIndexPair.Item2, includeSecondaryParentGene, rng); if (connGene.HasValue) { // Attempt to add the gene to the child genome we are building. _connGeneListBuilder.TryAddGene(connGene.Value); } } // Convert the genes to the structure required by NeatGenome. ConnectionGenes <T> connGenes = _connGeneListBuilder.ToConnectionGenes(); // Create and return a new genome. return(_genomeBuilder.Create( _genomeIdSeq.Next(), _generationSeq.Peek, connGenes)); }
public static NeatGenome <double> CreateNeatGenome( MetaNeatGenome <double> metaNeatGenome, INeatGenomeBuilder <double> genomeBuilder) { var connGenes = new ConnectionGenes <double>(12); connGenes[0] = (0, 3, 0.1); connGenes[1] = (0, 4, 0.2); connGenes[2] = (0, 5, 0.3); connGenes[3] = (3, 6, 0.4); connGenes[4] = (4, 7, 0.5); connGenes[5] = (5, 8, 0.6); connGenes[6] = (6, 9, 0.7); connGenes[7] = (7, 10, 0.8); connGenes[8] = (8, 11, 0.9); connGenes[9] = (9, 1, 1.0); connGenes[10] = (10, 1, 1.1); connGenes[11] = (11, 1, 1.2); var genome = genomeBuilder.Create(0, 0, connGenes); return(genome); }
/// <summary> /// Create a new child genome from a given parent genome. /// </summary> /// <param name="parent">The parent genome.</param> /// <returns>A new child genome.</returns> public NeatGenome <T> CreateChildGenome(NeatGenome <T> parent) { Debug.Assert(_metaNeatGenome == parent.MetaNeatGenome, "Parent genome has unexpected MetaNeatGenome."); // Attempt to find a new connection that we can add to the genome. DirectedConnection directedConn; if (!TryGetConnection(parent, out directedConn, out int insertIdx)) { // Failed to find a new connection. return(null); } // Determine the connection weight. // 50% of the time use weights very close to zero. // Note. this recreates the strategy used in SharpNEAT 2.x. // ENHANCEMENT: Reconsider the distribution of new weights and if there are better approaches (distributions) we could use. T weight = _rng.NextBool() ? _weightDistB.Sample() : _weightDistA.Sample(); // Create a new connection gene array that consists of the parent connection genes plus the new gene // inserted at the correct (sorted) position. var parentConnArr = parent.ConnectionGenes._connArr; var parentWeightArr = parent.ConnectionGenes._weightArr; int parentLen = parentConnArr.Length; // Create the child genome's ConnectionGenes object. int childLen = parentLen + 1; var connGenes = new ConnectionGenes <T>(childLen); var connArr = connGenes._connArr; var weightArr = connGenes._weightArr; // Copy genes up to insertIdx. Array.Copy(parentConnArr, connArr, insertIdx); Array.Copy(parentWeightArr, weightArr, insertIdx); // Copy the new genome into its insertion point. connArr[insertIdx] = new DirectedConnection( directedConn.SourceId, directedConn.TargetId); weightArr[insertIdx] = weight; // Copy remaining genes (if any). Array.Copy(parentConnArr, insertIdx, connArr, insertIdx + 1, parentLen - insertIdx); Array.Copy(parentWeightArr, insertIdx, weightArr, insertIdx + 1, parentLen - insertIdx); // Create and return a new genome. // Notes. // The set of hidden node IDs remains unchanged from the parent, therefore we are able to re-use parent.HiddenNodeIdArray. // However, the presence of a new connection invalidates parent.NodeIndexByIdMap for use in the new genome, because the allocated // node indexes are dependent on node depth in the acyclic graph, which in turn can be modified by the presence of a new connection. return(_genomeBuilder.Create( _genomeIdSeq.Next(), _generationSeq.Peek, connGenes, parent.HiddenNodeIdArray)); }
/// <summary> /// Create a new child genome from a given parent genome. /// </summary> /// <param name="parent">The parent genome.</param> /// <param name="rng">Random source.</param> /// <returns>A new child genome.</returns> public NeatGenome <T>?CreateChildGenome(NeatGenome <T> parent, IRandomSource rng) { // Attempt to find a new connection that we can add to the genome. if (!TryGetConnection(parent, rng, out DirectedConnection directedConn, out int insertIdx)) { // Failed to find a new connection. return(null); } // Determine the connection weight. // 50% of the time use weights very close to zero. // Note. this recreates the strategy used in SharpNEAT 2.x. // ENHANCEMENT: Reconsider the distribution of new weights and if there are better approaches (distributions) we could use. T weight = rng.NextBool() ? _weightSamplerB.Sample(rng) : _weightSamplerA.Sample(rng); // Create a new connection gene array that consists of the parent connection genes plus the new gene // inserted at the correct (sorted) position. var parentConnArr = parent.ConnectionGenes._connArr; var parentWeightArr = parent.ConnectionGenes._weightArr; int parentLen = parentConnArr.Length; // Create the child genome's ConnectionGenes object. int childLen = parentLen + 1; var connGenes = new ConnectionGenes <T>(childLen); var connArr = connGenes._connArr; var weightArr = connGenes._weightArr; // Copy genes up to insertIdx. Array.Copy(parentConnArr, connArr, insertIdx); Array.Copy(parentWeightArr, weightArr, insertIdx); // Copy the new genome into its insertion point. connArr[insertIdx] = new DirectedConnection( directedConn.SourceId, directedConn.TargetId); weightArr[insertIdx] = weight; // Copy remaining genes (if any). Array.Copy(parentConnArr, insertIdx, connArr, insertIdx + 1, parentLen - insertIdx); Array.Copy(parentWeightArr, insertIdx, weightArr, insertIdx + 1, parentLen - insertIdx); // Create and return a new genome. // Note. The set of hidden node IDs remains unchanged from the parent, therefore we are able to re-use // both parent.HiddenNodeIdArray and NodeIndexByIdMap. return(_genomeBuilder.Create( _genomeIdSeq.Next(), _generationSeq.Peek, connGenes, parent.HiddenNodeIdArray, parent.NodeIndexByIdMap)); }
/// <summary> /// Create a new child genome from a given parent genome. /// </summary> /// <param name="parent">The parent genome.</param> /// <param name="rng">Random source.</param> /// <returns>A new child genome.</returns> public NeatGenome <T>?CreateChildGenome(NeatGenome <T> parent, IRandomSource rng) { // We require at least two connections in the parent, i.e. we avoid creating genomes with // no connections, which would be pointless. if (parent.ConnectionGenes.Length < 2) { return(null); } // Select a gene at random to delete. var parentConnArr = parent.ConnectionGenes._connArr; var parentWeightArr = parent.ConnectionGenes._weightArr; int parentLen = parentConnArr.Length; int deleteIdx = rng.Next(parentLen); // Create the child genome's ConnectionGenes object. int childLen = parentLen - 1; var connGenes = new ConnectionGenes <T>(childLen); var connArr = connGenes._connArr; var weightArr = connGenes._weightArr; // Copy genes up to deleteIdx. Array.Copy(parentConnArr, connArr, deleteIdx); Array.Copy(parentWeightArr, weightArr, deleteIdx); // Copy remaining genes (if any). Array.Copy(parentConnArr, deleteIdx + 1, connArr, deleteIdx, childLen - deleteIdx); Array.Copy(parentWeightArr, deleteIdx + 1, weightArr, deleteIdx, childLen - deleteIdx); // Get an array of hidden node IDs. var hiddenNodeIdArr = GetHiddenNodeIdArray(parent, deleteIdx, connArr); // Create and return a new genome. return(_genomeBuilder.Create( _genomeIdSeq.Next(), _generationSeq.Peek, connGenes, hiddenNodeIdArr)); }
/// <summary> /// Creates a single randomly initialised genome. /// </summary> private NeatGenome <T> CreateGenome() { // Determine how many connections to create in the new genome, as a proportion of all possible connections // between the input and output nodes. int connectionCount = (int)NumericsUtils.ProbabilisticRound(_connectionDefArr.Length * _connectionsProportion, _rng); // Ensure there is at least one connection. connectionCount = Math.Max(1, connectionCount); // Select a random subset of all possible connections between the input and output nodes. int[] sampleArr = new int[connectionCount]; DiscreteDistributionUtils.SampleUniformWithoutReplacement( _connectionDefArr.Length, sampleArr, _rng); // Sort the samples. // Note. This results in the neural net connections being sorted by sourceID then targetID. Array.Sort(sampleArr); // Create the connection gene arrays and populate them. var connGenes = new ConnectionGenes <T>(connectionCount); var connArr = connGenes._connArr; var weightArr = connGenes._weightArr; for (int i = 0; i < sampleArr.Length; i++) { DirectedConnection cdef = _connectionDefArr[sampleArr[i]]; connArr[i] = new DirectedConnection( cdef.SourceId, cdef.TargetId); weightArr[i] = _connWeightDist.Sample(_metaNeatGenome.ConnectionWeightRange, true); } // Get create a new genome with a new ID, birth generation of zero. int id = _genomeIdSeq.Next(); return(_genomeBuilder.Create(id, 0, connGenes)); }