private static void WriteConnection(XmlElement xmlConnections, FloatFastConnection connectionGene) { XmlElement xmlConnection = XmlUtilities.AddElement(xmlConnections, "connection"); XmlUtilities.AddAttribute(xmlConnection, "src-id", connectionGene.sourceNeuronIdx.ToString()); XmlUtilities.AddAttribute(xmlConnection, "tgt-id", connectionGene.targetNeuronIdx.ToString()); XmlUtilities.AddAttribute(xmlConnection, "weight", connectionGene.weight.ToString()); }
/// <summary> /// Standard qquicksort algorithm. /// </summary> /// <param name="left"></param> /// <param name="right"></param> private static void QuickSortFastConnections(int left, int right) { do { int i = left; int j = right; FloatFastConnection x = fastConnectionArray[(i + j) >> 1]; do { while (CompareKeys(ref fastConnectionArray[i], ref x) < 0) { i++; } while (CompareKeys(ref x, ref fastConnectionArray[j]) < 0) { j--; } System.Diagnostics.Debug.Assert(i >= left && j <= right, "(i>=left && j<=right) Sort failed - Is your IComparer bogus?"); if (i > j) { break; } if (i < j) { FloatFastConnection key = fastConnectionArray[i]; fastConnectionArray[i] = fastConnectionArray[j]; fastConnectionArray[j] = key; } i++; j--; } while (i <= j); if (j - left <= right - i) { if (left < j) { QuickSortFastConnections(left, j); } left = i; } else { if (i < right) { QuickSortFastConnections(i, right); } right = j; } } while (left < right); }
// This is a quick sort algorithm that manipulates FastConnection structures. Although this // is the same sorting technique used internally by Array.Sort this is approximately 10 times // faster because it eliminates the need for boxing and unboxing of the structs. // So although this code could be replcaed by a single Array.Sort statement, the pay off // was though to be worth it. private static int CompareKeys(ref FloatFastConnection a, ref FloatFastConnection b) { int diff = a.sourceNeuronIdx - b.sourceNeuronIdx; if (diff == 0) { // Secondary sort on targetNeuronIdx. return(a.targetNeuronIdx - b.targetNeuronIdx); } else { return(diff); } }
static public ModularNetwork DecodeToModularNetwork(NeatGenome.NeatGenome g) { int inputCount = g.InputNeuronCount; int outputCount = g.OutputNeuronCount; int neuronCount = g.NeuronGeneList.Count; IActivationFunction[] activationFunctions = new IActivationFunction[neuronCount]; float[] biasList = new float[neuronCount]; Dictionary <long, int> neuronLookup = new Dictionary <long, int>(neuronCount); // Create an array of the activation functions for each non-module node node in the genome. // Start with a bias node if there is one in the genome. // The genome's neuron list is assumed to be ordered by type, with the bias node appearing first. int neuronGeneIndex = 0; for (; neuronGeneIndex < neuronCount; neuronGeneIndex++) { if (g.NeuronGeneList[neuronGeneIndex].NeuronType != NeuronType.Bias) { break; } activationFunctions[neuronGeneIndex] = g.NeuronGeneList[neuronGeneIndex].ActivationFunction; neuronLookup.Add(g.NeuronGeneList[neuronGeneIndex].InnovationId, neuronGeneIndex); } int biasCount = neuronGeneIndex; for (; neuronGeneIndex < neuronCount; neuronGeneIndex++) { activationFunctions[neuronGeneIndex] = g.NeuronGeneList[neuronGeneIndex].ActivationFunction; neuronLookup.Add(g.NeuronGeneList[neuronGeneIndex].InnovationId, neuronGeneIndex); biasList[neuronGeneIndex] = g.NeuronGeneList[neuronGeneIndex].Bias; } // Create an array of the activation functions, inputs, and outputs for each module in the genome. ModulePacket[] modules = new ModulePacket[g.ModuleGeneList.Count]; for (int i = g.ModuleGeneList.Count - 1; i >= 0; i--) { modules[i].function = g.ModuleGeneList[i].Function; // Must translate input and output IDs to array locations. modules[i].inputLocations = new int[g.ModuleGeneList[i].InputIds.Count]; for (int j = g.ModuleGeneList[i].InputIds.Count - 1; j >= 0; j--) { modules[i].inputLocations[j] = neuronLookup[g.ModuleGeneList[i].InputIds[j]]; } modules[i].outputLocations = new int[g.ModuleGeneList[i].OutputIds.Count]; for (int j = g.ModuleGeneList[i].OutputIds.Count - 1; j >= 0; j--) { modules[i].outputLocations[j] = neuronLookup[g.ModuleGeneList[i].OutputIds[j]]; } } // ConnectionGenes point to a neuron's innovation ID. Translate this ID to the neuron's index in the neuron array. FloatFastConnection[] connections = new FloatFastConnection[g.ConnectionGeneList.Count]; for (int connectionGeneIndex = g.ConnectionGeneList.Count - 1; connectionGeneIndex >= 0; connectionGeneIndex--) { ConnectionGene connectionGene = g.ConnectionGeneList[connectionGeneIndex]; connections[connectionGeneIndex].sourceNeuronIdx = neuronLookup[connectionGene.SourceNeuronId]; connections[connectionGeneIndex].targetNeuronIdx = neuronLookup[connectionGene.TargetNeuronId]; connections[connectionGeneIndex].weight = (float)connectionGene.Weight; connections[connectionGeneIndex].learningRate = connectionGene.learningRate; connections[connectionGeneIndex].A = connectionGene.A; connections[connectionGeneIndex].B = connectionGene.B; connections[connectionGeneIndex].C = connectionGene.C; connections[connectionGeneIndex].D = connectionGene.D; connections[connectionGeneIndex].modConnection = connectionGene.modConnection; } ModularNetwork mn = new ModularNetwork(biasCount, inputCount, outputCount, neuronCount, connections, biasList, activationFunctions, modules); if (g.networkAdaptable) { mn.adaptable = true; } if (g.networkModulatory) { mn.modulatory = true; } mn.genome = g; return(mn); }
static public FastConcurrentMultiplicativeNetwork DecodeToFastConcurrentMultiplicativeNetwork(NeatGenome.NeatGenome g, IActivationFunction activationFn) { int outputNeuronCount = g.OutputNeuronCount; int neuronGeneCount = g.NeuronGeneList.Count; // Slightly inefficient - determine the number of bias nodes. Fortunately there is not actually // any reason to ever have more than one bias node - although there may be 0. int neuronGeneIdx = 0; for (; neuronGeneIdx < neuronGeneCount; neuronGeneIdx++) { if (g.NeuronGeneList[neuronGeneIdx].NeuronType != NeuronType.Bias) { break; } } int biasNodeCount = neuronGeneIdx; int inputNeuronCount = g.InputNeuronCount; // ConnectionGenes point to a neuron ID. We need to map this ID to a 0 based index for // efficiency. To do this we build a table of indexes (ints) keyed on neuron ID. // TODO: An alternative here would be to forgo the building of a table and do a binary // search directly on the NeuronGeneList - probably a good idea to use a heuristic based upon // neuroncount*connectioncount that decides on which technique to use. Small networks will // likely be faster to decode using the binary search. // Actually we can partly achieve the above optimzation by using HybridDictionary instead of Hashtable. // Although creating a table is a bit expensive. HybridDictionary neuronIndexTable = new HybridDictionary(neuronGeneCount); for (int i = 0; i < neuronGeneCount; i++) { neuronIndexTable.Add(g.NeuronGeneList[i].InnovationId, i); } // Count how many of the connections are actually enabled. TODO: make faster - store disable count? int connectionGeneCount = g.ConnectionGeneList.Count; int connectionCount = connectionGeneCount; // for(int i=0; i<connectionGeneCount; i++) // { // if(g.ConnectionGeneList[i].Enabled) // connectionCount++; // } // Now we can build the connection array(s). FloatFastConnection[] connectionArray = new FloatFastConnection[connectionCount]; int connectionIdx = 0; for (int connectionGeneIdx = 0; connectionGeneIdx < connectionCount; connectionGeneIdx++) { ConnectionGene connectionGene = g.ConnectionGeneList[connectionIdx]; connectionArray[connectionIdx].sourceNeuronIdx = (int)neuronIndexTable[connectionGene.SourceNeuronId]; connectionArray[connectionIdx].targetNeuronIdx = (int)neuronIndexTable[connectionGene.TargetNeuronId]; connectionArray[connectionIdx].weight = (float)connectionGene.Weight; connectionIdx++; } // Now sort the connection array on sourceNeuronIdx, secondary sort on targetNeuronIdx. // TODO: custom sort routine to prevent boxing/unboxing required by Array.Sort(ValueType[]) //Array.Sort(connectionArray, fastConnectionComparer); QuickSortFastConnections(0, fastConnectionArray.Length - 1); return(new FastConcurrentMultiplicativeNetwork( biasNodeCount, inputNeuronCount, outputNeuronCount, neuronGeneCount, connectionArray, activationFn)); }
static public ModularNetwork DecodeToModularNetwork(NeatGenome.NeatGenome g) { int inputCount = g.InputNeuronCount; int outputCount = g.OutputNeuronCount; int neuronCount = g.NeuronGeneList.Count; IActivationFunction[] activationFunctions = new IActivationFunction[neuronCount]; float[] biasList = new float[neuronCount]; Dictionary <uint, int> neuronLookup = new Dictionary <uint, int>(neuronCount); // Schrum: In case there are output neurons out of order g.NeuronGeneList.NeuronSortCheck(); // Create an array of the activation functions for each non-module node node in the genome. // Start with a bias node if there is one in the genome. // The genome's neuron list is assumed to be ordered by type, with the bias node appearing first. int neuronGeneIndex = 0; for (; neuronGeneIndex < neuronCount; neuronGeneIndex++) { if (g.NeuronGeneList[neuronGeneIndex].NeuronType != NeuronType.Bias) { break; } activationFunctions[neuronGeneIndex] = g.NeuronGeneList[neuronGeneIndex].ActivationFunction; neuronLookup.Add(g.NeuronGeneList[neuronGeneIndex].InnovationId, neuronGeneIndex); } int biasCount = neuronGeneIndex; // Schrum: debug //Console.WriteLine("start (after bias): " + g.GenomeId); // Schrum: Debugging //NeuronType expectedType = NeuronType.Input; for (; neuronGeneIndex < neuronCount; neuronGeneIndex++) { activationFunctions[neuronGeneIndex] = g.NeuronGeneList[neuronGeneIndex].ActivationFunction; // Schrum: Debug /* * if (expectedType != g.NeuronGeneList[neuronGeneIndex].NeuronType) * { * if (expectedType == NeuronType.Input && g.NeuronGeneList[neuronGeneIndex].NeuronType == NeuronType.Output) * { * expectedType = NeuronType.Output; * } * else if (expectedType == NeuronType.Output && g.NeuronGeneList[neuronGeneIndex].NeuronType == NeuronType.Hidden) * { * expectedType = NeuronType.Hidden; * } * else * { * // Error condition: * Console.WriteLine("Error with genome: " + g.GenomeId); * * XmlDocument doc = new XmlDocument(); * XmlGenomeWriterStatic.Write(doc, (SharpNeatLib.NeatGenome.NeatGenome)g); * FileInfo oFileInfo = new FileInfo("ProblemGenome.xml"); * doc.Save(oFileInfo.FullName); * * Environment.Exit(1); * } * } */ neuronLookup.Add(g.NeuronGeneList[neuronGeneIndex].InnovationId, neuronGeneIndex); biasList[neuronGeneIndex] = g.NeuronGeneList[neuronGeneIndex].Bias; } // Create an array of the activation functions, inputs, and outputs for each module in the genome. ModulePacket[] modules = new ModulePacket[g.ModuleGeneList.Count]; for (int i = g.ModuleGeneList.Count - 1; i >= 0; i--) { modules[i].function = g.ModuleGeneList[i].Function; // Must translate input and output IDs to array locations. modules[i].inputLocations = new int[g.ModuleGeneList[i].InputIds.Count]; for (int j = g.ModuleGeneList[i].InputIds.Count - 1; j >= 0; j--) { modules[i].inputLocations[j] = neuronLookup[g.ModuleGeneList[i].InputIds[j]]; } modules[i].outputLocations = new int[g.ModuleGeneList[i].OutputIds.Count]; for (int j = g.ModuleGeneList[i].OutputIds.Count - 1; j >= 0; j--) { modules[i].outputLocations[j] = neuronLookup[g.ModuleGeneList[i].OutputIds[j]]; } } // ConnectionGenes point to a neuron's innovation ID. Translate this ID to the neuron's index in the neuron array. FloatFastConnection[] connections = new FloatFastConnection[g.ConnectionGeneList.Count]; for (int connectionGeneIndex = g.ConnectionGeneList.Count - 1; connectionGeneIndex >= 0; connectionGeneIndex--) { ConnectionGene connectionGene = g.ConnectionGeneList[connectionGeneIndex]; connections[connectionGeneIndex].sourceNeuronIdx = neuronLookup[connectionGene.SourceNeuronId]; connections[connectionGeneIndex].targetNeuronIdx = neuronLookup[connectionGene.TargetNeuronId]; connections[connectionGeneIndex].weight = (float)connectionGene.Weight; connections[connectionGeneIndex].learningRate = connectionGene.learningRate; connections[connectionGeneIndex].A = connectionGene.A; connections[connectionGeneIndex].B = connectionGene.B; connections[connectionGeneIndex].C = connectionGene.C; connections[connectionGeneIndex].D = connectionGene.D; connections[connectionGeneIndex].modConnection = connectionGene.modConnection; } ModularNetwork mn = new ModularNetwork(biasCount, inputCount, outputCount, g.OutputsPerPolicy, neuronCount, connections, biasList, activationFunctions, modules); if (g.networkAdaptable) { mn.adaptable = true; } if (g.networkModulatory) { mn.modulatory = true; } mn.genome = g; return(mn); }