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"));
        }
Beispiel #3
0
 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;
            }
        }