public FloatFastConcurrentNetwork( int biasNeuronCount, int inputNeuronCount, int outputNeuronCount, int outputsPerPolicy, // Schrum: Added int totalNeuronCount, FloatFastConnection[] connectionArray, IActivationFunction[] activationFnArray) { this.biasNeuronCount = biasNeuronCount; this.inputNeuronCount = inputNeuronCount; this.totalInputNeuronCount = biasNeuronCount + inputNeuronCount; this.outputNeuronCount = outputNeuronCount; this.outputsPerPolicy = outputsPerPolicy; // Schrum: Added this.connectionArray = connectionArray; this.activationFnArray = activationFnArray; //----- Allocate the arrays that make up the neural network. // The neuron signals are initialised to 0 by default. Only bias nodes need setting to 1. neuronSignalArray = new float[totalNeuronCount]; _neuronSignalArray = new float[totalNeuronCount]; for(int i=0; i<biasNeuronCount; i++) neuronSignalArray[i] = 1.0F; }
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("R")); }
public CTRNN(int biasNeuronCount, int inputNeuronCount, int outputNeuronCount, int totalNeuronCount, FloatFastConnection[] connections, float[] biasList, IActivationFunction[] activationFunctions, ModulePacket[] modules, float[] timeConstArray) : base(biasNeuronCount,inputNeuronCount,outputNeuronCount,totalNeuronCount,connections, biasList,activationFunctions, modules) { timeConstantArray = timeConstArray; activeSumsArray = new float[timeConstantArray.Length]; oldActivation = new float[timeConstantArray.Length]; }
public int Compare(object x, object y) { FloatFastConnection a = (FloatFastConnection)x; FloatFastConnection b = (FloatFastConnection)y; int diff = a.sourceNeuronIdx - b.sourceNeuronIdx; if (diff == 0) { // Secondary sort on targetNeuronIdx. return(a.targetNeuronIdx - b.targetNeuronIdx); } else { return(diff); } }
public FastConcurrentMultiplicativeNetwork( int biasNeuronCount, int inputNeuronCount, int outputNeuronCount, int totalNeuronCount, FloatFastConnection[] connectionArray, IActivationFunction activationFn) { this.biasNeuronCount = biasNeuronCount; this.inputNeuronCount = inputNeuronCount; this.totalInputNeuronCount = biasNeuronCount + inputNeuronCount; this.outputNeuronCount = outputNeuronCount; this.connectionArray = connectionArray; this.activationFn = activationFn; //----- Allocate the arrays that make up the neural network. // The neurons signals are initialised to 0 by default. Only bias nodes need setting to 1. neuronSignalArray = new float[totalNeuronCount]; _neuronSignalArray = new float[totalNeuronCount]; neuronSignalFlagArray = new BitArray(totalNeuronCount); for(int i=0; i<biasNeuronCount; i++) neuronSignalArray[i] = 1.0F; }
// 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 DecodeToCTRNN(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]; float[] timeConst = new float[neuronCount]; Dictionary<uint, int> neuronLookup = new Dictionary<uint, 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; timeConst[neuronGeneIndex] = g.NeuronGeneList[neuronGeneIndex].TimeConstant; } // 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; } CTRNN mn = new CTRNN(biasCount, inputCount, outputCount, neuronCount, connections, biasList, activationFunctions, modules,timeConst); 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; }
public ModularNetwork(int biasNeuronCount, int inputNeuronCount, int outputNeuronCount, int totalNeuronCount, FloatFastConnection[] connections, float[] biasList, IActivationFunction[] activationFunctions, ModulePacket[] modules) { this.biasNeuronCount = biasNeuronCount; this.inputNeuronCount = inputNeuronCount; this.totalInputNeuronCount = biasNeuronCount + inputNeuronCount; this.outputNeuronCount = outputNeuronCount; this.connections = connections; this.activationFunctions = activationFunctions; this.modules = modules; this.biasList = biasList; // Justin: Setup fields for recursive network activation calculated = new bool[totalNeuronCount]; dependencies = new List<int>[totalNeuronCount]; endNeurons = new List<int>(); for (int i = 0; i < totalNeuronCount; i++) { dependencies[i] = new List<int>(); calculated[i] = false; } // Calculate dependencies. We will temporarily use calculated[] to store whether or not neurons have dependent "children" (will re-initialize the array to false afterwards) for (int i = 0; i < connections.Length; i++) { calculated[connections[i].sourceNeuronIdx] = true; // Mark the source as having dependents dependencies[connections[i].targetNeuronIdx].Add(i); // Add the source as a dependency of the target } // Mark "ending neurons" by seeing which neurons have no dependents for (int i = 0; i < totalNeuronCount; i++) { if (calculated[i] == false) endNeurons.Add(i); calculated[i] = false; // Also, re-initialize calculated[] to false } //foreach (int i in endNeurons) Console.Write(i + " "); Console.WriteLine(); //Console.WriteLine("# Outputs: " + endNeurons.Count + " guessed: " + outputNeuronCount + " total: " + totalNeuronCount + " bias: " + biasNeuronCount); /*int counter = 0; for (int i = 0; i < dependencies.Length; i++) { if (dependencies[i].Count == 0) counter++; //foreach (int arr in dependencies[i]) Console.Write(arr + " "); //Console.WriteLine(); } Console.WriteLine("# Inputs: " + counter + " guessed: " + totalInputNeuronCount + " total: " + totalNeuronCount + " bias: " + biasNeuronCount); //*/ // Allocate the arrays that store the states at different points in the neural network. // The neuron signals are initialised to 0 by default. Only bias nodes need setting to 1. neuronSignals = new float[totalNeuronCount]; modSignals = new float[totalNeuronCount]; neuronSignalsBeingProcessed = new float[totalNeuronCount]; for (int i = 0; i < biasNeuronCount; i++) { neuronSignals[i] = 1.0F; } }
public ModularNetwork(int biasNeuronCount, int inputNeuronCount, int outputNeuronCount, int totalNeuronCount, FloatFastConnection[] connections, float[] biasList, IActivationFunction[] activationFunctions, ModulePacket[] modules) { this.biasNeuronCount = biasNeuronCount; this.inputNeuronCount = inputNeuronCount; this.totalInputNeuronCount = biasNeuronCount + inputNeuronCount; this.outputNeuronCount = outputNeuronCount; this.connections = connections; this.activationFunctions = activationFunctions; this.modules = modules; this.biasList = biasList; adaptable = false; modulatory = false; // Allocate the arrays that store the states at different points in the neural network. // The neuron signals are initialised to 0 by default. Only bias nodes need setting to 1. neuronSignals = new float[totalNeuronCount]; modSignals = new float[totalNeuronCount]; neuronSignalsBeingProcessed = new float[totalNeuronCount]; for (int i = 0; i < biasNeuronCount; i++) { neuronSignals[i] = 1.0F; } this.activated = new bool[TotalNeuronCount]; this.inActivation = new bool[TotalNeuronCount]; this.lastActivation = new float[TotalNeuronCount]; adjacentList = new List<int>[TotalNeuronCount]; reverseAdjacentList = new List<int>[TotalNeuronCount]; adjacentMatrix = new float[TotalNeuronCount, TotalNeuronCount]; for (int i = 0; i < TotalNeuronCount; i++) { this.activated[i] = this.inActivation[i] = false; this.lastActivation[i] = 0; this.adjacentList[i] = new List<int>(TotalNeuronCount); this.reverseAdjacentList[i] = new List<int>(TotalNeuronCount); // this.adjacentMatrix[i] = new List<float>(TotalNeuronCount); } // Set up adjacency list and matrix for (int i = 0; i < this.connections.Length; i++) { int crs = connections[i].sourceNeuronIdx; int crt = connections[i].targetNeuronIdx; // Holds outgoing nodes this.adjacentList[crs].Add(crt); // Holds incoming nodes this.reverseAdjacentList[crt].Add(crs); this.adjacentMatrix[crs, crt] = connections[i].weight; } }