public Substrate(uint input, uint output, uint hidden, IActivationFunction function) { weightRange = HyperNEATParameters.weightRange; threshold = HyperNEATParameters.threshold; inputCount = input; outputCount = output; hiddenCount = hidden; activationFunction = function; inputDelta = 2.0f / (inputCount); if (hiddenCount != 0) hiddenDelta = 2.0f / (hiddenCount); else hiddenDelta = 0; outputDelta = 2.0f / (outputCount); //SharpNEAT requires that the neuronlist be input|bias|output|hidden neurons=new NeuronGeneList((int)(inputCount + outputCount+ hiddenCount)); //setup the inputs for (uint a = 0; a < inputCount; a++) { neurons.Add(new NeuronGene(a, NeuronType.Input, activationFunction)); } //setup the outputs for (uint a = 0; a < outputCount; a++) { neurons.Add(new NeuronGene(a + inputCount, NeuronType.Output, activationFunction)); } for (uint a = 0; a < hiddenCount; a++) { neurons.Add(new NeuronGene(a + inputCount+outputCount, NeuronType.Hidden, activationFunction)); } }
public Substrate(uint biasCount, uint inputCount, uint outputCount, uint hiddenCount, IActivationFunction function) { this.biasCount = biasCount; this.inputCount = inputCount; this.outputCount = outputCount; this.hiddenCount = hiddenCount; this.activationFunction = function; weightRange = HyperNEATParameters.weightRange; threshold = HyperNEATParameters.threshold; if (inputCount != 0) { inputDelta = 2.0f / (inputCount); } if (hiddenCount != 0) { hiddenDelta = 2.0f / (hiddenCount); } if (outputCount != 0) { outputDelta = 2.0f / (outputCount); } // SharpNEAT requires that the neuron list be in this order: bias|input|output|hidden neurons = new NeuronGeneList((int)(inputCount + outputCount + hiddenCount)); // set up the bias nodes for (uint a = 0; a < biasCount; a++) { neurons.Add(new NeuronGene(a, NeuronType.Bias, ActivationFunctionFactory.GetActivationFunction("NullFn"), 0.0f)); } // set up the input nodes for (uint a = 0; a < inputCount; a++) { neurons.Add(new NeuronGene(a + biasCount, NeuronType.Input, ActivationFunctionFactory.GetActivationFunction("NullFn"), 0.0f)); } // set up the output nodes for (uint a = 0; a < outputCount; a++) { neurons.Add(new NeuronGene(a + biasCount + inputCount, NeuronType.Output, activationFunction, 1.0f)); } // set up the hidden nodes for (uint a = 0; a < hiddenCount; a++) { neurons.Add(new NeuronGene(a + biasCount + inputCount + outputCount, NeuronType.Hidden, activationFunction, 0.5f)); } }
public MultiLayerSandwichSubstrate(int rows, int cols, int numLayers, bool useBias, IActivationFunction activationFunction) { m_rows = rows; m_cols = cols; m_numLayers = numLayers; m_useBias = useBias; m_rowDelta = 2.0f / m_rows; m_colDelta = 2.0f / m_cols; m_activationFunction = activationFunction; // add only one bias m_neurons = new NeuronGeneList(m_numLayers * (m_rows * m_cols) + (m_useBias ? 1 : 0)); uint curNeurId = 0; // inserting the bias if needed if (m_useBias) { m_neurons.Add(new NeuronGene(curNeurId++, NeuronType.Bias, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // inserting input layer neurons for (int i = 0, len = m_rows * m_cols; i < len; i++) { m_neurons.Add(new NeuronGene(curNeurId++, NeuronType.Input, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // inserting output layer neurons for (int i = 0, len = m_rows * m_cols; i < len; i++) { m_neurons.Add(new NeuronGene(curNeurId++, NeuronType.Output, m_activationFunction)); } // inserting hidden layer neurons for (int li = 0; li < m_numLayers - 2; li++) { for (int i = 0, len = m_rows * m_cols; i < len; i++) { m_neurons.Add(new NeuronGene(curNeurId++, NeuronType.Hidden, m_activationFunction)); } } }
public static NeatGenome Read(XmlElement xmlGenome) { int inputNeuronCount = 0; int outputNeuronCount = 0; uint id = uint.Parse(XmlUtilities.GetAttributeValue(xmlGenome, "id")); // Schrum: Retrieve this new property, which is saved to xml files now int outputsPerPolicy = int.Parse(XmlUtilities.GetAttributeValue(xmlGenome, "outputsperpolicy")); //--- Read neuron genes into a list. NeuronGeneList neuronGeneList = new NeuronGeneList(); XmlNodeList listNeuronGenes = xmlGenome.SelectNodes("neurons/neuron"); foreach (XmlElement xmlNeuronGene in listNeuronGenes) { NeuronGene neuronGene = ReadNeuronGene(xmlNeuronGene); // Count the input and output neurons as we go. switch (neuronGene.NeuronType) { case NeuronType.Input: inputNeuronCount++; break; case NeuronType.Output: outputNeuronCount++; break; } neuronGeneList.Add(neuronGene); } //--- Read module genes into a list. List <ModuleGene> moduleGeneList = new List <ModuleGene>(); XmlNodeList listModuleGenes = xmlGenome.SelectNodes("modules/module"); foreach (XmlElement xmlModuleGene in listModuleGenes) { moduleGeneList.Add(ReadModuleGene(xmlModuleGene)); } //--- Read connection genes into a list. ConnectionGeneList connectionGeneList = new ConnectionGeneList(); XmlNodeList listConnectionGenes = xmlGenome.SelectNodes("connections/connection"); foreach (XmlElement xmlConnectionGene in listConnectionGenes) { connectionGeneList.Add(ReadConnectionGene(xmlConnectionGene)); } //return new NeatGenome(id, neuronGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount); //return new NeatGenome(id, neuronGeneList, moduleGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount); // Schrum: Changed to include the outputs per policy return(new NeatGenome(id, neuronGeneList, moduleGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount, outputsPerPolicy)); }
public static NeatGenome Read(XmlElement xmlGenome) { int inputNeuronCount=0; int outputNeuronCount=0; uint id = uint.Parse(XmlUtilities.GetAttributeValue(xmlGenome, "id")); //--- Read neuron genes into a list. NeuronGeneList neuronGeneList = new NeuronGeneList(); XmlNodeList listNeuronGenes = xmlGenome.SelectNodes("neurons/neuron"); foreach(XmlElement xmlNeuronGene in listNeuronGenes) { NeuronGene neuronGene = ReadNeuronGene(xmlNeuronGene); // Count the input and output neurons as we go. switch(neuronGene.NeuronType) { case NeuronType.Input: inputNeuronCount++; break; case NeuronType.Output: outputNeuronCount++; break; } neuronGeneList.Add(neuronGene); } //--- Read module genes into a list. List<ModuleGene> moduleGeneList = new List<ModuleGene>(); XmlNodeList listModuleGenes = xmlGenome.SelectNodes("modules/module"); foreach (XmlElement xmlModuleGene in listModuleGenes) { moduleGeneList.Add(ReadModuleGene(xmlModuleGene)); } //--- Read connection genes into a list. ConnectionGeneList connectionGeneList = new ConnectionGeneList(); XmlNodeList listConnectionGenes = xmlGenome.SelectNodes("connections/connection"); foreach(XmlElement xmlConnectionGene in listConnectionGenes) connectionGeneList.Add(ReadConnectionGene(xmlConnectionGene)); //return new NeatGenome(id, neuronGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount); NeatGenome g = new NeatGenome(id, neuronGeneList, moduleGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount); g.Behavior = ReadBehavior(xmlGenome.SelectSingleNode("behavior")); g.Behavior.objectives = new double[6]; g.objectives = new double[6]; // JUSTIN: Read grid/trajectory info g.GridCoords = ReadGrid(xmlGenome.SelectSingleNode("grid")); g.Behavior.trajectory = ReadTrajectory(xmlGenome.SelectSingleNode("trajectory")); return g; }
public Substrate(uint biasCount, uint inputCount, uint outputCount, uint hiddenCount, IActivationFunction function) { this.biasCount = biasCount; this.inputCount = inputCount; this.outputCount = outputCount; this.hiddenCount = hiddenCount; this.activationFunction = function; weightRange = HyperNEATParameters.weightRange; threshold = HyperNEATParameters.threshold; if (inputCount != 0) inputDelta = 2.0f / (inputCount); if (hiddenCount != 0) hiddenDelta = 2.0f / (hiddenCount); if (outputCount != 0) outputDelta = 2.0f / (outputCount); // SharpNEAT requires that the neuron list be in this order: bias|input|output|hidden neurons = new NeuronGeneList((int)(inputCount + outputCount + hiddenCount)); // set up the bias nodes for (uint a = 0; a < biasCount; a++) { neurons.Add(new NeuronGene(a, NeuronType.Bias, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // set up the input nodes for (uint a = 0; a < inputCount; a++) { neurons.Add(new NeuronGene(a + biasCount, NeuronType.Input, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // set up the output nodes for (uint a = 0; a < outputCount; a++) { neurons.Add(new NeuronGene(a + biasCount + inputCount, NeuronType.Output, activationFunction)); } // set up the hidden nodes for (uint a = 0; a < hiddenCount; a++) { neurons.Add(new NeuronGene(a + biasCount + inputCount + outputCount, NeuronType.Hidden, activationFunction)); } }
public Substrate(uint input, uint output, uint hidden, IActivationFunction function) { weightRange = HyperNEATParameters.weightRange; threshold = HyperNEATParameters.threshold; inputCount = input; outputCount = output; hiddenCount = hidden; activationFunction = function; inputDelta = 2.0f / (inputCount); if (hiddenCount != 0) { hiddenDelta = 2.0f / (hiddenCount); } else { hiddenDelta = 0; } outputDelta = 2.0f / (outputCount); //SharpNEAT requires that the neuronlist be input|bias|output|hidden neurons = new NeuronGeneList((int)(inputCount + outputCount + hiddenCount)); //setup the inputs for (uint a = 0; a < inputCount; a++) { neurons.Add(new NeuronGene(a, NeuronType.Input, activationFunction)); } //setup the outputs for (uint a = 0; a < outputCount; a++) { neurons.Add(new NeuronGene(a + inputCount, NeuronType.Output, activationFunction)); } for (uint a = 0; a < hiddenCount; a++) { neurons.Add(new NeuronGene(a + inputCount + outputCount, NeuronType.Hidden, activationFunction)); } }
public static NeatGenome Read(XmlElement xmlGenome) { int inputNeuronCount = 0; int outputNeuronCount = 0; long id = long.Parse(XmlUtilities.GetAttributeValue(xmlGenome, "id")); //--- Read neuron genes into a list. NeuronGeneList neuronGeneList = new NeuronGeneList(); XmlNodeList listNeuronGenes = xmlGenome.SelectNodes("neurons/neuron"); foreach (XmlElement xmlNeuronGene in listNeuronGenes) { NeuronGene neuronGene = ReadNeuronGene(xmlNeuronGene); // Count the input and output neurons as we go. switch (neuronGene.NeuronType) { case NeuronType.Input: inputNeuronCount++; break; case NeuronType.Output: outputNeuronCount++; break; } neuronGeneList.Add(neuronGene); } //--- Read module genes into a list. List <ModuleGene> moduleGeneList = new List <ModuleGene>(); XmlNodeList listModuleGenes = xmlGenome.SelectNodes("modules/module"); foreach (XmlElement xmlModuleGene in listModuleGenes) { moduleGeneList.Add(ReadModuleGene(xmlModuleGene)); } //--- Read connection genes into a list. ConnectionGeneList connectionGeneList = new ConnectionGeneList(); XmlNodeList listConnectionGenes = xmlGenome.SelectNodes("connections/connection"); foreach (XmlElement xmlConnectionGene in listConnectionGenes) { connectionGeneList.Add(ReadConnectionGene(xmlConnectionGene)); } //return new NeatGenome(id, neuronGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount); return(new NeatGenome(id, neuronGeneList, moduleGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount)); }
// ControllerSubstrate constructor public PlanterSubstrate(uint input, uint output, uint hidden, IActivationFunction function, uint rgbSize = 10, uint hX = 5, uint hY = 2) : base(input, output, hidden, function) { rgbOneDimension = rgbSize; colorArraySize = rgbOneDimension * rgbOneDimension; headingArraySize = hX * hY; headingX = hX; headingY = hY; neurons.Clear(); // SharpNEAT requires that the neuron list be in this order: bias|input|output|hidden neurons = new NeuronGeneList((int)(inputCount + outputCount + hiddenCount)); // set up the bias nodes for (uint a = 0; a < biasCount; a++) { neurons.Add(new NeuronGene(a, NeuronType.Bias, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // set up the input nodes for (uint a = 0; a < inputCount; a++) { neurons.Add(new NeuronGene(a + biasCount, NeuronType.Input, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // set up the output nodes for (uint a = 0; a < outputCount; a++) { neurons.Add(new NeuronGene(a + biasCount + inputCount, NeuronType.Output, ActivationFunctionFactory.GetActivationFunction("BipolarSigmoid"))); } // set up the hidden nodes for (uint a = 0; a < hiddenCount; a++) { neurons.Add(new NeuronGene(a + biasCount + inputCount + outputCount, NeuronType.Hidden, ActivationFunctionFactory.GetActivationFunction("BipolarSigmoid"))); } }
public static NeatGenome Read(XmlElement xmlGenome) { int inputNeuronCount=0; int outputNeuronCount=0; uint id = uint.Parse(XmlUtilities.GetAttributeValue(xmlGenome, "id")); // Schrum: Retrieve this new property, which is saved to xml files now int outputsPerPolicy = int.Parse(XmlUtilities.GetAttributeValue(xmlGenome, "outputsperpolicy")); //--- Read neuron genes into a list. NeuronGeneList neuronGeneList = new NeuronGeneList(); XmlNodeList listNeuronGenes = xmlGenome.SelectNodes("neurons/neuron"); foreach(XmlElement xmlNeuronGene in listNeuronGenes) { NeuronGene neuronGene = ReadNeuronGene(xmlNeuronGene); // Count the input and output neurons as we go. switch(neuronGene.NeuronType) { case NeuronType.Input: inputNeuronCount++; break; case NeuronType.Output: outputNeuronCount++; break; } neuronGeneList.Add(neuronGene); } //--- Read module genes into a list. List<ModuleGene> moduleGeneList = new List<ModuleGene>(); XmlNodeList listModuleGenes = xmlGenome.SelectNodes("modules/module"); foreach (XmlElement xmlModuleGene in listModuleGenes) { moduleGeneList.Add(ReadModuleGene(xmlModuleGene)); } //--- Read connection genes into a list. ConnectionGeneList connectionGeneList = new ConnectionGeneList(); XmlNodeList listConnectionGenes = xmlGenome.SelectNodes("connections/connection"); foreach(XmlElement xmlConnectionGene in listConnectionGenes) connectionGeneList.Add(ReadConnectionGene(xmlConnectionGene)); //return new NeatGenome(id, neuronGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount); //return new NeatGenome(id, neuronGeneList, moduleGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount); // Schrum: Changed to include the outputs per policy return new NeatGenome(id, neuronGeneList, moduleGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount, outputsPerPolicy); }
public static NeatGenome Read(XmlElement xmlGenome) { int inputNeuronCount=0; int outputNeuronCount=0; uint id = uint.Parse(XmlUtilities.GetAttributeValue(xmlGenome, "id")); //--- Read neuron genes into a list. NeuronGeneList neuronGeneList = new NeuronGeneList(); XmlNodeList listNeuronGenes = xmlGenome.SelectNodes("neurons/neuron"); foreach(XmlElement xmlNeuronGene in listNeuronGenes) { NeuronGene neuronGene = ReadNeuronGene(xmlNeuronGene); // Count the input and output neurons as we go. switch(neuronGene.NeuronType) { case NeuronType.Input: inputNeuronCount++; break; case NeuronType.Output: outputNeuronCount++; break; } neuronGeneList.Add(neuronGene); } //--- Read connection genes into a list. ConnectionGeneList connectionGeneList = new ConnectionGeneList(); XmlNodeList listConnectionGenes = xmlGenome.SelectNodes("connections/connection"); foreach(XmlElement xmlConnectionGene in listConnectionGenes) connectionGeneList.Add(ReadConnectionGene(xmlConnectionGene)); return new NeatGenome(id, neuronGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount); }
// NOTE: Multi-Plane Substrates ARE MAYBE supported by this method! private NeatGenome.NeatGenome generateHomogeneousGenome(INetwork network, bool normalizeWeights, bool adaptiveNetwork,bool modulatoryNet) { IActivationFunction activationFunction = HyperNEATParameters.substrateActivationFunction; ConnectionGeneList connections = new ConnectionGeneList((int)((InputCount * HiddenCount) + (HiddenCount * OutputCount))); float[] coordinates = new float[4]; //JUSTIN: CHANGE THIS BACK TO [4]!!! float output; uint connectionCounter = 0; int iterations = 2 * (network.TotalNeuronCount - (network.InputNeuronCount + network.OutputNeuronCount)) + 1; uint totalOutputCount = OutputCount; uint totalInputCount = InputCount; uint totalHiddenCount = HiddenCount; uint sourceCount, targetCout; double weightRange = HyperNEATParameters.weightRange; double threshold = HyperNEATParameters.threshold; NeuronGeneList neurons; // SharpNEAT requires that the neuron list be in this order: bias|input|output|hidden neurons = new NeuronGeneList((int)(InputCount + OutputCount + HiddenCount)); // set up the input nodes for (uint a = 0; a < totalInputCount; a++) { neurons.Add(new NeuronGene(a, NeuronType.Input, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // set up the output nodes for (uint a = 0; a < totalOutputCount; a++) { neurons.Add(new NeuronGene(a + InputCount, NeuronType.Output, activationFunction)); } // set up the hidden nodes for (uint a = 0; a < totalHiddenCount; a++) { neurons.Add(new NeuronGene(a + InputCount + OutputCount, NeuronType.Hidden, activationFunction)); } // CPPN Outputs: [ Weights ] [ Biases ] // When using multi-plane substrates, there will be multiple Weight and Bias outputs. // There is a Weight output for every plane-to-plane connection (including a plane connected to itself, as in regular substrates) // There is a Bias output for every plane // Since "regular substrates" only have 1 plane, they only have 1 Weight and 1 Bias output. MP substrates have more. :) int numPlanes = planes.Count; int numPlaneConnections = planesConnected.Count; int computedIndex; uint sourceID = uint.MaxValue, targetID = uint.MaxValue; NeuronGroup connectedNG; foreach (NeuronGroup ng in neuronGroups) { foreach (uint connectedTo in ng.ConnectedTo) { connectedNG = getNeuronGroup(connectedTo); sourceCount = 0; foreach (PointF source in ng.NeuronPositions) { //-----------------Get the bias of the source node /*switch (ng.GroupType) { case 0: sourceID = ng.GlobalID + sourceCount; break; //Input case 1: sourceID = totalInputCount + ng.GlobalID + sourceCount; break; //Output case 2: sourceID = totalInputCount + totalOutputCount + ng.GlobalID + sourceCount; break; //Hidden } coordinates[0] = source.X; coordinates[1] = source.Y; coordinates[2] = 0.0f; coordinates[3] = 0.0f; network.ClearSignals(); network.SetInputSignals(coordinates); network.RecursiveActivation();//network.MultipleSteps(iterations); neurons[(int)sourceID].Bias = (float)(network.GetOutputSignal(1) * weightRange); //*///---------------------------- targetCout = 0; foreach (PointF target in connectedNG.NeuronPositions) { switch (ng.GroupType) { case 0: sourceID = ng.GlobalID + sourceCount; break; //Input case 1: sourceID = totalInputCount + ng.GlobalID + sourceCount; break; //Output case 2: sourceID = totalInputCount + totalOutputCount + ng.GlobalID + sourceCount; break; //Hidden } switch (connectedNG.GroupType) { case 0: targetID = connectedNG.GlobalID + targetCout; break; case 1: targetID = totalInputCount + connectedNG.GlobalID + targetCout; break; case 2: targetID = totalInputCount + totalOutputCount + connectedNG.GlobalID + targetCout; break; } //-----------------Get the bias of the target node coordinates[0] = target.X; coordinates[1] = target.Y; coordinates[2] = 0.0f; coordinates[3] = 0.0f; //coordinates[4] = 0.0f; coordinates[5] = 0.0f; //JUSTIN: REMOVE THIS!!! //String s = arrayToString(coordinates); //if (weights.ContainsKey(s)) // neurons[(int)targetID].Bias = weights[s]; //else { network.ClearSignals(); network.SetInputSignals(coordinates); network.RecursiveActivation();//network.MultipleSteps(iterations); computedIndex = numPlaneConnections + planes.IndexOf(connectedNG.Plane); //neurons[(int)targetID].Bias = (float)(network.GetOutputSignal(1) * weightRange); neurons[(int)targetID].Bias = (float)(network.GetOutputSignal(computedIndex) * weightRange); //weights.Add(s,neurons[(int)targetID].Bias); } //---------------------------- coordinates[0] = source.X; coordinates[1] = source.Y; coordinates[2] = target.X; coordinates[3] = target.Y; //coordinates[4] = source.X - target.X; coordinates[5] = source.Y - target.Y; //JUSTIN: REMOVE THIS!!! network.ClearSignals(); network.SetInputSignals(coordinates); network.RecursiveActivation();//network.MultipleSteps(iterations); computedIndex = indexOfPlaneConnection(ng.Plane, connectedNG.Plane); //output = network.GetOutputSignal(0); output = network.GetOutputSignal(computedIndex); if (Math.Abs(output) > threshold) { float weight = (float)(((Math.Abs(output) - (threshold)) / (1 - threshold)) * weightRange * Math.Sign(output)); connections.Add(new ConnectionGene(connectionCounter++, sourceID, targetID, weight, ref coordinates)); } //else //{ // Console.WriteLine("Not connected"); //} targetCout++; } sourceCount++; } } } if (normalizeWeights) { normalizeWeightConnections(ref connections, neurons.Count); } NeatGenome.NeatGenome gn = new SharpNeatLib.NeatGenome.NeatGenome(0, neurons, connections, (int)(totalInputCount), (int)(totalOutputCount)); gn.networkAdaptable = adaptiveNetwork; gn.networkModulatory = modulatoryNet; return gn; }
public static IGenome CreateGenomePreserveID(NeatParameters neatParameters, IdGenerator idGenerator, int inputNeuronCount, int outputNeuronCount, float connectionProportion) { IActivationFunction actFunct; NeuronGene neuronGene; // temp variable. NeuronGeneList inputNeuronGeneList = new NeuronGeneList(); // includes bias neuron. NeuronGeneList outputNeuronGeneList = new NeuronGeneList(); NeuronGeneList neuronGeneList = new NeuronGeneList(); ConnectionGeneList connectionGeneList = new ConnectionGeneList(); int nodeCount = 0; WINManager win = WINManager.SharedWIN; // IMPORTANT NOTE: The neurons must all be created prior to any connections. That way all of the genomes // will obtain the same innovation ID's for the bias,input and output nodes in the initial population. // Create a single bias neuron. //TODO: DAVID proper activation function change to NULL? actFunct = ActivationFunctionFactory.GetActivationFunction("NullFn"); //neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Bias, actFunct); WINNode neuronNode = win.findOrInsertNodeWithProperties(idGenerator, WINNode.NodeWithProperties(nodeCount++, NeuronType.Bias) ); neuronGene = new NeuronGene(null, neuronNode.UniqueID, NeuronGene.INPUT_LAYER, NeuronType.Bias, actFunct); inputNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); // Create input neuron genes. actFunct = ActivationFunctionFactory.GetActivationFunction("NullFn"); for (int i = 0; i < inputNeuronCount; i++) { //TODO: DAVID proper activation function change to NULL? //neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Input, actFunct); neuronNode = win.findOrInsertNodeWithProperties(idGenerator, WINNode.NodeWithProperties(nodeCount++, NeuronType.Input)); neuronGene = new NeuronGene(null, neuronNode.UniqueID, NeuronGene.INPUT_LAYER, NeuronType.Input, actFunct); inputNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); } // Create output neuron genes. //actFunct = ActivationFunctionFactory.GetActivationFunction("NullFn"); for (int i = 0; i < outputNeuronCount; i++) { actFunct = ActivationFunctionFactory.GetActivationFunction("BipolarSigmoid"); //actFunct = ActivationFunctionFactory.GetRandomActivationFunction(neatParameters); //TODO: DAVID proper activation function //neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Output, actFunct); neuronNode = win.findOrInsertNodeWithProperties(idGenerator, WINNode.NodeWithProperties(nodeCount++, NeuronType.Output)); neuronGene = new NeuronGene(null, neuronNode.UniqueID, NeuronGene.OUTPUT_LAYER, NeuronType.Output, actFunct); outputNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); } int currentConnCount = 0; WINConnection winConn; // Loop over all possible connections from input to output nodes and create a number of connections based upon // connectionProportion. foreach (NeuronGene targetNeuronGene in outputNeuronGeneList) { foreach (NeuronGene sourceNeuronGene in inputNeuronGeneList) { // Always generate an ID even if we aren't going to use it. This is necessary to ensure connections // between the same neurons always have the same ID throughout the generated population. //PAUL NOTE: //instead of generating and not using and id, we use the target and connection properties to uniquely identify a connection in WIN //uint connectionInnovationId = idGenerator.NextInnovationId; if (Utilities.NextDouble() < connectionProportion) { // Ok lets create a connection. //first we search or create the winconnection object winConn = win.findOrInsertConnectionWithProperties(idGenerator, WINConnection.ConnectionWithProperties(currentConnCount, sourceNeuronGene.InnovationId, targetNeuronGene.InnovationId)); //our winconn will have our innovationID, and our weight like normal //this will also respect the idgenerator, since it gets sent in as well, for legacy purposes connectionGeneList.Add(new ConnectionGene(winConn.UniqueID, sourceNeuronGene.InnovationId, targetNeuronGene.InnovationId, (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0) ); //(Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0)); // Weight 0 +-5 } currentConnCount++; } } //WIN will eventually be in control of all the genomes that are created as well, but not quite yet! //TODO: WIN should be generating genomeIDs explicitly // Don't create any hidden nodes at this point. Fundamental to the NEAT way is to start minimally! return new NeatGenome(idGenerator.NextGenomeId, neuronGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount); }
public override IGenome CreateOffspring_Sexual(EvolutionAlgorithm ea, IGenome parent) { NeatGenome otherParent = parent as NeatGenome; if (otherParent == null) return null; // Build a list of connections in either this genome or the other parent. CorrelationResults correlationResults = CorrelateConnectionGeneLists(connectionGeneList, otherParent.connectionGeneList); Debug.Assert(correlationResults.PerformIntegrityCheck(), "CorrelationResults failed integrity check."); //----- Connection Genes. // We will temporarily store the offspring's genes in newConnectionGeneList and keeping track of which genes // exist with newConnectionGeneTable. Here we ensure these objects are created, and if they already existed // then ensure they are cleared. Clearing existing objects is more efficient that creating new ones because // allocated memory can be re-used. // Key = connection key, value = index in newConnectionGeneList. if(newConnectionGeneTable==null) { // Provide a capacity figure to the new Hashtable. The offspring will be the same length (or thereabouts). newConnectionGeneTable = new Hashtable(connectionGeneList.Count); } else { newConnectionGeneTable.Clear(); } //TODO: No 'capacity' constructor on CollectionBase. Create modified/custom CollectionBase. // newConnectionGeneList must be constructed on each call because it is passed to a new NeatGenome // at construction time and a permanent reference to the list is kept. newConnectionGeneList = new ConnectionGeneList(ConnectionGeneList.Count); // A switch that stores which parent is fittest 1 or 2. Chooses randomly if both are equal. More efficient to calculate this just once. byte fitSwitch; if(Fitness > otherParent.Fitness) fitSwitch = 1; else if(Fitness < otherParent.Fitness) fitSwitch = 2; else { // Select one of the parents at random to be the 'master' genome during crossover. if(Utilities.NextDouble() < 0.5) fitSwitch = 1; else fitSwitch = 2; } bool combineDisjointExcessFlag = Utilities.NextDouble() < ea.NeatParameters.pDisjointExcessGenesRecombined; // Loop through the correlationResults, building a table of ConnectionGenes from the parents that will make it into our // new [single] offspring. We use a table keyed on connection end points to prevent passing connections to the offspring // that may have the same end points but a different innovation number - effectively we filter out duplicate connections. int idxBound = correlationResults.CorrelationItemList.Count; for(int i=0; i<idxBound; i++) { CreateOffspring_Sexual_ProcessCorrelationItem((CorrelationItem)correlationResults.CorrelationItemList[i], fitSwitch, combineDisjointExcessFlag, ea.NeatParameters); } //----- Neuron Genes. // Build a neuronGeneList by analysing each connection's neuron end-point IDs. // This strategy has the benefit of eliminating neurons that are no longer connected too. // Remember to always keep all input, output and bias neurons though! NeuronGeneList newNeuronGeneList = new NeuronGeneList(neuronGeneList.Count); // Keep a table of the NeuronGene ID's keyed by ID so that we can keep track of which ones have been added. // Key = innovation ID, value = null for some reason. if(newNeuronGeneTable==null) newNeuronGeneTable = new Hashtable(neuronGeneList.Count); else newNeuronGeneTable.Clear(); // Get the input/output neurons from this parent. All Genomes share these neurons, they do not change during a run. idxBound = neuronGeneList.Count; for(int i=0; i<idxBound; i++) { if(neuronGeneList[i].NeuronType != NeuronType.Hidden) { newNeuronGeneList.Add(new NeuronGene(neuronGeneList[i])); newNeuronGeneTable.Add(neuronGeneList[i].InnovationId, null); } else { // No more bias, input or output nodes. break the loop. break; } } // Now analyse the connections to determine which NeuronGenes are required in the offspring. // Loop through every connection in the child, and add to the child those hidden neurons that are sources or targets of the connection. idxBound = newConnectionGeneList.Count; for(int i=0; i<idxBound; i++) { NeuronGene neuronGene; ConnectionGene connectionGene = newConnectionGeneList[i]; if(!newNeuronGeneTable.ContainsKey(connectionGene.SourceNeuronId)) { //TODO: DAVID proper activation function // We can safely assume that any missing NeuronGenes at this point are hidden heurons. neuronGene = this.neuronGeneList.GetNeuronById(connectionGene.SourceNeuronId); if (neuronGene != null) newNeuronGeneList.Add(new NeuronGene(neuronGene)); else newNeuronGeneList.Add(new NeuronGene(otherParent.NeuronGeneList.GetNeuronById(connectionGene.SourceNeuronId))); //newNeuronGeneList.Add(new NeuronGene(connectionGene.SourceNeuronId, NeuronType.Hidden, ActivationFunctionFactory.GetActivationFunction("SteepenedSigmoid"))); newNeuronGeneTable.Add(connectionGene.SourceNeuronId, null); } if(!newNeuronGeneTable.ContainsKey(connectionGene.TargetNeuronId)) { //TODO: DAVID proper activation function // We can safely assume that any missing NeuronGenes at this point are hidden heurons. neuronGene = this.neuronGeneList.GetNeuronById(connectionGene.TargetNeuronId); if (neuronGene != null) newNeuronGeneList.Add(new NeuronGene(neuronGene)); else newNeuronGeneList.Add(new NeuronGene(otherParent.NeuronGeneList.GetNeuronById(connectionGene.TargetNeuronId))); //newNeuronGeneList.Add(new NeuronGene(connectionGene.TargetNeuronId, NeuronType.Hidden, ActivationFunctionFactory.GetActivationFunction("SteepenedSigmoid"))); newNeuronGeneTable.Add(connectionGene.TargetNeuronId, null); } } // Determine which modules to pass on to the child in the same way. // For each module in this genome or in the other parent, if it was referenced by even one connection add it and all its dummy neurons to the child. List<ModuleGene> newModuleGeneList = new List<ModuleGene>(); // Build a list of modules the child might have, which is a union of the parents' module lists, but they are all copies so we can't just do a union. List<ModuleGene> unionParentModules = new List<ModuleGene>(moduleGeneList); foreach (ModuleGene moduleGene in otherParent.moduleGeneList) { bool alreadySeen = false; foreach (ModuleGene match in unionParentModules) { if (moduleGene.InnovationId == match.InnovationId) { alreadySeen = true; break; } } if (!alreadySeen) { unionParentModules.Add(moduleGene); } } foreach (ModuleGene moduleGene in unionParentModules) { // Examine each neuron in the child to determine whether it is part of a module. foreach (List<uint> dummyNeuronList in new List<uint>[] { moduleGene.InputIds, moduleGene.OutputIds }) { foreach (uint dummyNeuronId in dummyNeuronList) { if (newNeuronGeneTable.ContainsKey(dummyNeuronId)) { goto childHasModule; } } } continue; // the child does not contain this module, so continue the loop and check for the next module. childHasModule: // the child does contain this module, so make sure the child gets all the nodes the module requires to work. // Make sure the child has all the neurons in the given module. newModuleGeneList.Add(new ModuleGene(moduleGene)); foreach (List<uint> dummyNeuronList in new List<uint>[] { moduleGene.InputIds, moduleGene.OutputIds }) { foreach (uint dummyNeuronId in dummyNeuronList) { if (!newNeuronGeneTable.ContainsKey(dummyNeuronId)) { newNeuronGeneTable.Add(dummyNeuronId, null); NeuronGene neuronGene = this.neuronGeneList.GetNeuronById(dummyNeuronId); if (neuronGene != null) { newNeuronGeneList.Add(new NeuronGene(neuronGene)); } else { newNeuronGeneList.Add(new NeuronGene(otherParent.NeuronGeneList.GetNeuronById(dummyNeuronId))); } } } } } // TODO: Inefficient code? newNeuronGeneList.SortByInnovationId(); // Schrum: Need to calculate this because of Module Mutation adding extra outputs int revisedOutputCount = 0; foreach(NeuronGene n in newNeuronGeneList) { if (n.NeuronType == NeuronType.Output) revisedOutputCount++; } // newConnectionGeneList is already sorted because it was generated by passing over the list returned by // CorrelateConnectionGeneLists() - which is always in order. // Schrum: Modified to add outputsPerPolicy as a parameter, and use revisedOutputCount return new NeatGenome(ea.NextGenomeId, newNeuronGeneList, newModuleGeneList, newConnectionGeneList, inputNeuronCount, revisedOutputCount, outputsPerPolicy); }
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); }
public NeatGenome.NeatGenome generateMultiGenomeStack(INetwork network, List <float> stackCoordinates, bool normalizeWeights, bool adaptiveNetwork, bool modulatoryNet) { uint numberOfAgents = (uint)stackCoordinates.Count; IActivationFunction activationFunction = HyperNEATParameters.substrateActivationFunction; ConnectionGeneList connections = new ConnectionGeneList((int)(numberOfAgents * (InputCount * HiddenCount) + numberOfAgents * (HiddenCount * OutputCount))); float[] coordinates = new float[5]; float output; uint connectionCounter = 0; float agentDelta = 2.0f / (numberOfAgents - 1); int iterations = 2 * (network.TotalNeuronCount - (network.InputNeuronCount + network.OutputNeuronCount)) + 1; uint totalOutputCount = OutputCount * numberOfAgents; uint totalInputCount = InputCount * numberOfAgents; uint totalHiddenCount = HiddenCount * numberOfAgents; // Schrum: debugging /* * Console.WriteLine("generateMultiGenomeStack"); * Console.WriteLine("numberOfAgents:" + numberOfAgents); * Console.WriteLine("totalOutputCount:" + totalOutputCount); * Console.WriteLine("totalInputCount:" + totalInputCount); */ uint sourceCount, targetCout; double weightRange = HyperNEATParameters.weightRange; double threshold = HyperNEATParameters.threshold; NeuronGeneList neurons; // SharpNEAT requires that the neuron list be in this order: bias|input|output|hidden neurons = new NeuronGeneList((int)(InputCount * numberOfAgents + OutputCount * numberOfAgents + HiddenCount * numberOfAgents)); // set up the input nodes for (uint a = 0; a < totalInputCount; a++) { neurons.Add(new NeuronGene(a, NeuronType.Input, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // set up the output nodes for (uint a = 0; a < totalOutputCount; a++) { neurons.Add(new NeuronGene(a + InputCount * numberOfAgents, NeuronType.Output, activationFunction)); } // set up the hidden nodes for (uint a = 0; a < totalHiddenCount; a++) { neurons.Add(new NeuronGene(a + InputCount * numberOfAgents + OutputCount * numberOfAgents, NeuronType.Hidden, activationFunction)); } bool[] biasCalculated = new bool[totalHiddenCount + totalOutputCount + totalInputCount]; uint agent = 0; float A = 0.0f, B = 0.0f, C = 0.0f, D = 0.0f, learningRate = 0.0f, modConnection; foreach (float stackCoordinate in stackCoordinates) { coordinates[4] = stackCoordinate; uint sourceID = uint.MaxValue, targetID = uint.MaxValue; NeuronGroup connectedNG; foreach (NeuronGroup ng in neuronGroups) { foreach (uint connectedTo in ng.ConnectedTo) { connectedNG = getNeuronGroup(connectedTo); sourceCount = 0; foreach (PointF source in ng.NeuronPositions) { targetCout = 0; foreach (PointF target in connectedNG.NeuronPositions) { switch (ng.GroupType) { case 0: sourceID = (agent * InputCount) + ng.GlobalID + sourceCount; break; //Input case 1: sourceID = totalInputCount + (agent * OutputCount) + ng.GlobalID + sourceCount; break; //Output case 2: sourceID = totalInputCount + totalOutputCount + (agent * HiddenCount) + ng.GlobalID + sourceCount; break; //Hidden } switch (connectedNG.GroupType) { case 0: targetID = (agent * InputCount) + connectedNG.GlobalID + targetCout; break; case 1: targetID = totalInputCount + (agent * OutputCount) + connectedNG.GlobalID + targetCout; break; case 2: targetID = totalInputCount + totalOutputCount + (agent * HiddenCount) + connectedNG.GlobalID + targetCout; break; } //target node bias if (!biasCalculated[targetID]) { coordinates[0] = 0.0f; coordinates[1] = 0.0f; coordinates[2] = target.X; coordinates[3] = target.Y; network.ClearSignals(); network.SetInputSignals(coordinates); ((ModularNetwork)network).RecursiveActivation(); neurons[(int)targetID].Bias = (float)(network.GetOutputSignal(1) * weightRange); biasCalculated[targetID] = true; } coordinates[0] = source.X; coordinates[1] = source.Y; coordinates[2] = target.X; coordinates[3] = target.Y; network.ClearSignals(); network.SetInputSignals(coordinates); ((ModularNetwork)network).RecursiveActivation(); //network.MultipleSteps(iterations); output = network.GetOutputSignal(0); double leo = 0.0; if (adaptiveNetwork) { A = network.GetOutputSignal(2); B = network.GetOutputSignal(3); C = network.GetOutputSignal(4); D = network.GetOutputSignal(5); learningRate = network.GetOutputSignal(6); } if (modulatoryNet) { modConnection = network.GetOutputSignal(7); } else { modConnection = 0.0f; } if (useLeo) { threshold = 0.0; leo = network.GetOutputSignal(2); } if (!useLeo || leo > 0.0) { if (Math.Abs(output) > threshold) { float weight = (float)(((Math.Abs(output) - (threshold)) / (1 - threshold)) * weightRange * Math.Sign(output)); //if (adaptiveNetwork) //{ // //If adaptive network set weight to small value // weight = 0.1f; //} connections.Add(new ConnectionGene(connectionCounter++, sourceID, targetID, weight, ref coordinates, A, B, C, D, modConnection, learningRate)); } } //else //{ // Console.WriteLine("Not connected"); //} targetCout++; } sourceCount++; } } } agent++; } if (normalizeWeights) { normalizeWeightConnections(ref connections, neurons.Count); } SharpNeatLib.NeatGenome.NeatGenome sng = new SharpNeatLib.NeatGenome.NeatGenome(0, neurons, connections, (int)(totalInputCount), (int)(totalOutputCount)); sng.networkAdaptable = adaptiveNetwork; sng.networkModulatory = modulatoryNet; // Schrum: debugging //Console.WriteLine("sng.InputNeuronCount:" + sng.InputNeuronCount); //Console.WriteLine("sng.OutputNeuronCount:" + sng.OutputNeuronCount); return(sng); }
private NeatGenome.NeatGenome generateHomogeneousGenomeES(INetwork network, bool normalizeWeights, bool adaptiveNetwork, bool modulatoryNet) { List <PointF> hiddenNeuronPositions = new List <PointF>(); IActivationFunction activationFunction = HyperNEATParameters.substrateActivationFunction; ConnectionGeneList connections = new ConnectionGeneList();//(int)((InputCount * HiddenCount) + (HiddenCount * OutputCount))); List <PointF> outputNeuronPositions = getNeuronGroupByType(1); List <PointF> inputNeuronPositions = getNeuronGroupByType(0); EvolvableSubstrate se = new EvolvableSubstrate(); se.generateConnections(inputNeuronPositions, outputNeuronPositions, network, HyperNEATParameters.initialRes, (float)HyperNEATParameters.varianceThreshold, (float)HyperNEATParameters.bandingThreshold, (int)HyperNEATParameters.ESIterations, (float)HyperNEATParameters.divisionThreshold, HyperNEATParameters.maximumRes, InputCount, OutputCount, -1.0f, -1.0f, 1.0f, 1.0f, ref connections, ref hiddenNeuronPositions); HiddenCount = (uint)hiddenNeuronPositions.Count; float[] coordinates = new float[5]; uint connectionCounter = (uint)connections.Count; NeuronGeneList neurons; // SharpNEAT requires that the neuron list be in this order: bias|input|output|hidden neurons = new NeuronGeneList((int)(InputCount + OutputCount + HiddenCount)); // set up the input nodes for (uint a = 0; a < InputCount; a++) { neurons.Add(new NeuronGene(a, NeuronType.Input, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // set up the output nodes for (uint a = 0; a < OutputCount; a++) { neurons.Add(new NeuronGene(a + InputCount, NeuronType.Output, activationFunction)); } // set up the hidden nodes for (uint a = 0; a < HiddenCount; a++) { neurons.Add(new NeuronGene(a + InputCount + OutputCount, NeuronType.Hidden, activationFunction)); } bool[] visited = new bool[neurons.Count]; List <uint> nodeList = new List <uint>(); bool[] connectedToInput = new bool[neurons.Count]; bool[] isOutput = new bool[neurons.Count]; bool danglingConnection = true; while (danglingConnection) { bool[] hasIncomming = new bool[neurons.Count]; foreach (ConnectionGene co in connections) { // if (co.SourceNeuronId != co.TargetNeuronId) // { hasIncomming[co.TargetNeuronId] = true; // } } for (int i = 0; i < InputCount; i++) { hasIncomming[i] = true; } bool[] hasOutgoing = new bool[neurons.Count]; foreach (ConnectionGene co in connections) { // if (co.TargetNeuronId != co.SourceNeuronId) // { if (co.TargetNeuronId != co.SourceNeuronId) //neurons that only connect to themselfs don't count { hasOutgoing[co.SourceNeuronId] = true; } // } } //Keep output neurons for (int i = 0; i < OutputCount; i++) { hasOutgoing[i + InputCount] = true; } danglingConnection = false; //Check if there are still dangling connections foreach (ConnectionGene co in connections) { if (!hasOutgoing[co.TargetNeuronId] || !hasIncomming[co.SourceNeuronId]) { danglingConnection = true; break; } } connections.RemoveAll(delegate(ConnectionGene m) { return(!hasIncomming[m.SourceNeuronId]); }); connections.RemoveAll(delegate(ConnectionGene m) { return(!hasOutgoing[m.TargetNeuronId]); }); } if (normalizeWeights) { normalizeWeightConnections(ref connections, neurons.Count); } SharpNeatLib.NeatGenome.NeatGenome gn = new SharpNeatLib.NeatGenome.NeatGenome(0, neurons, connections, (int)(InputCount), (int)(OutputCount)); // SharpNeatLib.NeatGenome.NeatGenome sng = new SharpNeatLib.NeatGenome.NeatGenome(0, neurons, connections, (int)(totalInputCount), (int)(totalOutputCount)); gn.networkAdaptable = adaptiveNetwork; gn.networkModulatory = modulatoryNet; return(gn); }
/// <summary> /// Reads a NeatGenome from XML. /// </summary> /// <param name="xr">The XmlReader to read from.</param> /// <param name="nodeFnIds">Indicates if node activation function IDs should be read. They are required /// for HyperNEAT genomes but not for NEAT</param> public static NeatGenome ReadGenome(XmlReader xr, bool nodeFnIds) { // Find <Network>. XmlIoUtils.MoveToElement(xr, false, __ElemNetwork); int initialDepth = xr.Depth; // Read genome ID attribute if present. Otherwise default to zero; it's the caller's responsibility to // check IDs are unique and in-line with the genome factory's ID generators. string genomeIdStr = xr.GetAttribute(__AttrId); uint genomeId; uint.TryParse(genomeIdStr, out genomeId); // Read birthGeneration attribute if present. Otherwise default to zero. string birthGenStr = xr.GetAttribute(__AttrBirthGeneration); uint birthGen; uint.TryParse(birthGenStr, out birthGen); // Find <Nodes>. XmlIoUtils.MoveToElement(xr, true, __ElemNodes); // Create a reader over the <Nodes> sub-tree. int inputNodeCount = 0; int outputNodeCount = 0; NeuronGeneList nGeneList = new NeuronGeneList(); using(XmlReader xrSubtree = xr.ReadSubtree()) { // Re-scan for the root <Nodes> element. XmlIoUtils.MoveToElement(xrSubtree, false); // Move to first node elem. XmlIoUtils.MoveToElement(xrSubtree, true, __ElemNode); // Read node elements. do { NodeType neuronType = NetworkXmlIO.ReadAttributeAsNodeType(xrSubtree, __AttrType); uint id = XmlIoUtils.ReadAttributeAsUInt(xrSubtree, __AttrId); int functionId = 0; double[] auxState = null; if(nodeFnIds) { // Read activation fn ID. functionId = XmlIoUtils.ReadAttributeAsInt(xrSubtree, __AttrActivationFunctionId); // Read aux state as comma seperated list of real values. auxState = XmlIoUtils.ReadAttributeAsDoubleArray(xrSubtree, __AttrAuxState); } NeuronGene nGene = new NeuronGene(id, neuronType, functionId, auxState); nGeneList.Add(nGene); // Track the number of input and output nodes. switch(neuronType) { case NodeType.Input: inputNodeCount++; break; case NodeType.Output: outputNodeCount++; break; } } while(xrSubtree.ReadToNextSibling(__ElemNode)); } // Find <Connections>. XmlIoUtils.MoveToElement(xr, false, __ElemConnections); // Create a reader over the <Connections> sub-tree. ConnectionGeneList cGeneList = new ConnectionGeneList(); using(XmlReader xrSubtree = xr.ReadSubtree()) { // Re-scan for the root <Connections> element. XmlIoUtils.MoveToElement(xrSubtree, false); // Move to first connection elem. string localName = XmlIoUtils.MoveToElement(xrSubtree, true); if(localName == __ElemConnection) { // We have at least one connection. // Read connection elements. do { uint id = XmlIoUtils.ReadAttributeAsUInt(xrSubtree, __AttrId); uint srcId = XmlIoUtils.ReadAttributeAsUInt(xrSubtree, __AttrSourceId); uint tgtId = XmlIoUtils.ReadAttributeAsUInt(xrSubtree, __AttrTargetId); double weight = XmlIoUtils.ReadAttributeAsDouble(xrSubtree, __AttrWeight); ConnectionGene cGene = new ConnectionGene(id, srcId, tgtId, weight); cGeneList.Add(cGene); } while(xrSubtree.ReadToNextSibling(__ElemConnection)); } } // Move the reader beyond the closing tags </Connections> and </Network>. do { if (xr.Depth <= initialDepth) { break; } } while(xr.Read()); // Construct and return loaded NeatGenome. return new NeatGenome(null, genomeId, birthGen, nGeneList, cGeneList, inputNodeCount, outputNodeCount, true, true); }
public static NeatGenome Read(XmlElement xmlGenome) { int inputNeuronCount = 0; int outputNeuronCount = 0; uint id = uint.Parse(XmlUtilities.GetAttributeValue(xmlGenome, "id")); //--- Read neuron genes into a list. NeuronGeneList neuronGeneList = new NeuronGeneList(); XmlNodeList listNeuronGenes = xmlGenome.SelectNodes("neurons/neuron"); foreach (XmlElement xmlNeuronGene in listNeuronGenes) { NeuronGene neuronGene = ReadNeuronGene(xmlNeuronGene); // Count the input and output neurons as we go. switch (neuronGene.NeuronType) { case NeuronType.Input: inputNeuronCount++; break; case NeuronType.Output: outputNeuronCount++; break; } neuronGeneList.Add(neuronGene); } //--- Read module genes into a list. List <ModuleGene> moduleGeneList = new List <ModuleGene>(); XmlNodeList listModuleGenes = xmlGenome.SelectNodes("modules/module"); foreach (XmlElement xmlModuleGene in listModuleGenes) { moduleGeneList.Add(ReadModuleGene(xmlModuleGene)); } //--- Read connection genes into a list. ConnectionGeneList connectionGeneList = new ConnectionGeneList(); XmlNodeList listConnectionGenes = xmlGenome.SelectNodes("connections/connection"); foreach (XmlElement xmlConnectionGene in listConnectionGenes) { connectionGeneList.Add(ReadConnectionGene(xmlConnectionGene)); } //return new NeatGenome(id, neuronGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount); NeatGenome g = new NeatGenome(id, neuronGeneList, moduleGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount); g.Behavior = ReadBehavior(xmlGenome.SelectSingleNode("behavior")); g.Behavior.objectives = new double[6]; g.objectives = new double[6]; // JUSTIN: Read grid/trajectory info g.GridCoords = ReadGrid(xmlGenome.SelectSingleNode("grid")); g.Behavior.trajectory = ReadTrajectory(xmlGenome.SelectSingleNode("trajectory")); return(g); }
public override IGenome CreateOffspring_Sexual(EvolutionAlgorithm ea, IGenome parent) { CorrelationResults correlationResults = CorrelateConnectionGeneLists(connectionGeneList, ((NeatGenome)parent).connectionGeneList); Debug.Assert(correlationResults.PerformIntegrityCheck(), "CorrelationResults failed integrity check."); //----- Connection Genes. // We will temporarily store the offspring's genes in newConnectionGeneList and keeping track of which genes // exist with newConnectionGeneTable. Here we ensure these objects are created, and if they already existed // then ensure they are cleared. Clearing existing objects is more efficient that creating new ones because // allocated memory can be re-used. if(newConnectionGeneTable==null) { // Provide a capacity figure to the new Hashtable. The offspring will be the same length (or thereabouts). newConnectionGeneTable = new Hashtable(connectionGeneList.Count); } else { newConnectionGeneTable.Clear(); } //TODO: No 'capacity' constructor on CollectionBase. Create modified/custom CollectionBase. // newConnectionGeneList must be constructed on each call because it is passed to a new NeatGenome // at construction time and a permanent reference to the list is kept. newConnectionGeneList = new ConnectionGeneList(ConnectionGeneList.Count); // A switch that stores which parent is fittest 1 or 2. 0 if both are equal. More efficient to calculate this just once. byte fitSwitch; if(Fitness > parent.Fitness) fitSwitch = 1; else if(Fitness < parent.Fitness) fitSwitch = 2; else { // Select one of the parents at random to be the 'master' genome during crossover. if(Utilities.NextDouble() < 0.5) fitSwitch = 1; else fitSwitch = 2; } bool combineDisjointExcessFlag = Utilities.NextDouble() < ea.NeatParameters.pDisjointExcessGenesRecombined ? true : false; // Loop through the correlationResults, building a table of ConnectionGenes from the parent's that will make it into our // new [single] offspring. We use a table keyed on connection end points to prevent passing connections to the offspring // that may have the same end points but a different innovation number - effectively we filter out duplicate connections. int idxBound = correlationResults.CorrelationItemList.Count; for(int i=0; i<idxBound; i++) { CreateOffspring_Sexual_ProcessCorrelationItem((CorrelationItem)correlationResults.CorrelationItemList[i], fitSwitch, combineDisjointExcessFlag, ea.NeatParameters); } //----- Neuron Genes. // Build a neuronGeneList by analysing each connection's neuron end-point IDs. // This strategy has the benefit of eliminating neurons that are no longer connected too. // Remember to always keep all input, output and bias neurons though! NeuronGeneList newNeuronGeneList = new NeuronGeneList(neuronGeneList.Count); // Keep a table of the NeuronGene ID's keyed by ID so that we can keep track of which ones have been added. if(newNeuronGeneTable==null) newNeuronGeneTable = new Hashtable(neuronGeneList.Count); else newNeuronGeneTable.Clear(); // Get the input/output neurons from this parent. All Genomes share these neurons, they do not change during a run. idxBound = neuronGeneList.Count; for(int i=0; i<idxBound; i++) { if(neuronGeneList[i].NeuronType != NeuronType.Hidden) { newNeuronGeneList.Add(new NeuronGene(neuronGeneList[i])); newNeuronGeneTable.Add(neuronGeneList[i].InnovationId, null); } else { // No more bias, input or output nodes. break the loop. break; } } // Now analyse the connections to determine which NeuronGenes are required in the offspring. idxBound = newConnectionGeneList.Count; for(int i=0; i<idxBound; i++) { NeuronGene neuronGene; ConnectionGene connectionGene = newConnectionGeneList[i]; if(!newNeuronGeneTable.ContainsKey(connectionGene.SourceNeuronId)) { //TODO: DAVID proper activation function // We can safely assume that any missing NeuronGenes at this point are hidden heurons. neuronGene = this.neuronGeneList.GetNeuronById(connectionGene.SourceNeuronId); if (neuronGene != null) newNeuronGeneList.Add(new NeuronGene(neuronGene)); else newNeuronGeneList.Add(new NeuronGene(((NeatGenome)parent).NeuronGeneList.GetNeuronById(connectionGene.SourceNeuronId))); //newNeuronGeneList.Add(new NeuronGene(connectionGene.SourceNeuronId, NeuronType.Hidden, ActivationFunctionFactory.GetActivationFunction("SteepenedSigmoid"))); newNeuronGeneTable.Add(connectionGene.SourceNeuronId, null); } if(!newNeuronGeneTable.ContainsKey(connectionGene.TargetNeuronId)) { //TODO: DAVID proper activation function // We can safely assume that any missing NeuronGenes at this point are hidden heurons. neuronGene = this.neuronGeneList.GetNeuronById(connectionGene.TargetNeuronId); if (neuronGene != null) newNeuronGeneList.Add(new NeuronGene(neuronGene)); else newNeuronGeneList.Add(new NeuronGene(((NeatGenome)parent).NeuronGeneList.GetNeuronById(connectionGene.TargetNeuronId))); //newNeuronGeneList.Add(new NeuronGene(connectionGene.TargetNeuronId, NeuronType.Hidden, ActivationFunctionFactory.GetActivationFunction("SteepenedSigmoid"))); newNeuronGeneTable.Add(connectionGene.TargetNeuronId, null); } } // TODO: Inefficient code? newNeuronGeneList.SortByInnovationId(); // newConnectionGeneList is already sorted because it was generated by passing over the list returned by // CorrelateConnectionGeneLists() - which is always in order. return new NeatGenome(ea.NextGenomeId, newNeuronGeneList, newConnectionGeneList, inputNeuronCount, outputNeuronCount); }
// MPS support on the Hive methods only #region Generate heterogenous genomes with z-stack // MPS NOT supported by this method private NeatGenome.NeatGenome generateMultiGenomeStack(INetwork network, List<float> stackCoordinates, bool normalizeWeights, bool adaptiveNetwork, bool modulatoryNet) { if (useMultiPlaneSubstrate) throw new Exception("MPS not implemented for these parameters"); uint numberOfAgents = (uint)stackCoordinates.Count; IActivationFunction activationFunction = HyperNEATParameters.substrateActivationFunction; ConnectionGeneList connections = new ConnectionGeneList((int)(numberOfAgents * (InputCount * HiddenCount) + numberOfAgents * (HiddenCount * OutputCount))); float[] coordinates = new float[5]; float output; uint connectionCounter = 0; float agentDelta = 2.0f / (numberOfAgents - 1); int iterations = 2 * (network.TotalNeuronCount - (network.InputNeuronCount + network.OutputNeuronCount)) + 1; uint totalOutputCount = OutputCount * numberOfAgents; uint totalInputCount = InputCount * numberOfAgents; uint totalHiddenCount = HiddenCount * numberOfAgents; uint sourceCount, targetCout; double weightRange = HyperNEATParameters.weightRange; double threshold = HyperNEATParameters.threshold; NeuronGeneList neurons; // SharpNEAT requires that the neuron list be in this order: bias|input|output|hidden neurons = new NeuronGeneList((int)(InputCount * numberOfAgents + OutputCount * numberOfAgents + HiddenCount * numberOfAgents)); // set up the input nodes for (uint a = 0; a < totalInputCount; a++) { neurons.Add(new NeuronGene(a, NeuronType.Input, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // set up the output nodes for (uint a = 0; a < totalOutputCount; a++) { neurons.Add(new NeuronGene(a + InputCount * numberOfAgents, NeuronType.Output, activationFunction)); } // set up the hidden nodes for (uint a = 0; a < totalHiddenCount; a++) { neurons.Add(new NeuronGene(a + InputCount * numberOfAgents + OutputCount * numberOfAgents, NeuronType.Hidden, activationFunction)); } uint agent = 0; float A = 0.0f, B = 0.0f, C = 0.0f, D = 0.0f, learningRate = 0.0f, modConnection; foreach (float stackCoordinate in stackCoordinates) { coordinates[4] = stackCoordinate; uint sourceID = uint.MaxValue, targetID = uint.MaxValue; NeuronGroup connectedNG; foreach (NeuronGroup ng in neuronGroups) { foreach (uint connectedTo in ng.ConnectedTo) { connectedNG = getNeuronGroup(connectedTo); sourceCount = 0; foreach (PointF source in ng.NeuronPositions) { //-----------------Get the bias of the source node switch (ng.GroupType) { case 0: sourceID = (agent * InputCount) + ng.GlobalID + sourceCount; break; //Input case 1: sourceID = totalInputCount + (agent * OutputCount) + ng.GlobalID + sourceCount; break; //Output case 2: sourceID = totalInputCount + totalOutputCount + (agent * HiddenCount) + ng.GlobalID + sourceCount; break; //Hidden } coordinates[0] = source.X; coordinates[1] = source.Y; coordinates[2] = 0.0f; coordinates[3] = 0.0f; network.ClearSignals(); network.SetInputSignals(coordinates); network.RecursiveActivation();//network.MultipleSteps(iterations); neurons[(int)sourceID].Bias = (float)(network.GetOutputSignal(1) * weightRange); //---------------------------- targetCout = 0; foreach (PointF target in connectedNG.NeuronPositions) { switch (ng.GroupType) { case 0: sourceID = (agent * InputCount) + ng.GlobalID + sourceCount; break; //Input case 1: sourceID = totalInputCount + (agent * OutputCount) + ng.GlobalID + sourceCount; break; //Output case 2: sourceID = totalInputCount + totalOutputCount + (agent * HiddenCount) + ng.GlobalID + sourceCount; break; //Hidden } switch (connectedNG.GroupType) { case 0: targetID = (agent * InputCount) + connectedNG.GlobalID + targetCout; break; case 1: targetID = totalInputCount + (agent * OutputCount) + connectedNG.GlobalID + targetCout; break; case 2: targetID = totalInputCount + totalOutputCount + (agent * HiddenCount) + connectedNG.GlobalID + targetCout; break; } coordinates[0] = source.X; coordinates[1] = source.Y; coordinates[2] = target.X; coordinates[3] = target.Y; network.ClearSignals(); network.SetInputSignals(coordinates); network.RecursiveActivation();//network.MultipleSteps(iterations); output = network.GetOutputSignal(0); double leo = 0.0; if (adaptiveNetwork) { A = network.GetOutputSignal(2); B = network.GetOutputSignal(3); C = network.GetOutputSignal(4); D = network.GetOutputSignal(5); learningRate = network.GetOutputSignal(6); } if (modulatoryNet) { modConnection = network.GetOutputSignal(7); } else { modConnection = 0.0f; } if (useLeo) { threshold = 0.0; leo = network.GetOutputSignal(2); } if (!useLeo || leo > 0.0) if (Math.Abs(output) > threshold) { float weight = (float)(((Math.Abs(output) - (threshold)) / (1 - threshold)) * weightRange * Math.Sign(output)); //if (adaptiveNetwork) //{ // //If adaptive network set weight to small value // weight = 0.1f; //} connections.Add(new ConnectionGene(connectionCounter++, sourceID, targetID, weight, ref coordinates)); } //else //{ // Console.WriteLine("Not connected"); //} targetCout++; } sourceCount++; } } } agent++; } if (normalizeWeights) { normalizeWeightConnections(ref connections, neurons.Count); } SharpNeatLib.NeatGenome.NeatGenome sng = new SharpNeatLib.NeatGenome.NeatGenome(0, neurons, connections, (int)(totalInputCount), (int)(totalOutputCount)); sng.networkAdaptable = adaptiveNetwork; sng.networkModulatory = modulatoryNet; return sng; }
/// <summary> /// TODO /// </summary> /// <param name="birthGeneration"> /// The current evolution algorithm generation. /// Assigned to the new genome as its birth generation. /// </param> public override NeatGenome CreateGenome(uint birthGeneration) { NeuronGeneList neuronGeneList = new NeuronGeneList(_inputNeuronCount + _outputNeuronCount); NeuronGeneList inputNeuronGeneList = new NeuronGeneList(_inputNeuronCount); // includes single bias neuron. NeuronGeneList outputNeuronGeneList = new NeuronGeneList(_outputNeuronCount); // Create a single bias neuron. uint biasNeuronId = _innovationIdGenerator.NextId; if (0 != biasNeuronId) { // The ID generator must be reset before calling this method so that all generated genomes use the // same innovation ID for matching neurons and structures. throw new SharpNeatException("IdGenerator must be reset before calling CreateGenome(uint)"); } // Note. Genes within nGeneList must always be arranged according to the following layout plan. // Bias - single neuron. Innovation ID = 0 // Input neurons. // Output neurons. // Hidden neurons. NeuronGene neuronGene = CreateNeuronGene(biasNeuronId, NodeType.Bias); inputNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); // Create input neuron genes. for (int i = 0; i < _inputNeuronCount; i++) { neuronGene = CreateNeuronGene(_innovationIdGenerator.NextId, NodeType.Input); inputNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); } // Create output neuron genes. for (int i = 0; i < _outputNeuronCount; i++) { neuronGene = CreateNeuronGene(_innovationIdGenerator.NextId, NodeType.Output); outputNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); } // Define all possible connections between the input and output neurons (fully interconnected). int srcCount = inputNeuronGeneList.Count; int tgtCount = outputNeuronGeneList.Count; ConnectionDefinition[] connectionDefArr = new ConnectionDefinition[srcCount * tgtCount]; for (int srcIdx = 0, i = 0; srcIdx < srcCount; srcIdx++) { for (int tgtIdx = 0; tgtIdx < tgtCount; tgtIdx++) { connectionDefArr[i++] = new ConnectionDefinition(_innovationIdGenerator.NextId, srcIdx, tgtIdx); } } // Shuffle the array of possible connections. Utilities.Shuffle(connectionDefArr, _rng); // Select connection definitions from the head of the list and convert them to real connections. // We want some proportion of all possible connections but at least one (Connectionless genomes are not allowed). int connectionCount = (int)Utilities.ProbabilisticRound( (double)connectionDefArr.Length * _neatGenomeParamsComplexifying.InitialInterconnectionsProportion, _rng); connectionCount = Math.Max(1, connectionCount); // Create the connection gene list and populate it. ConnectionGeneList connectionGeneList = new ConnectionGeneList(connectionCount); #region Add connection to bisas short connections NeuronGene srcNeuronGeneACBias = inputNeuronGeneList[0]; if (!srcNeuronGeneACBias.TargetNeurons.Contains(outputNeuronGeneList[2].InnovationId)) { NeuronGene tgtNeuronGeneAC = outputNeuronGeneList[2]; ConnectionGene biasGene = new ConnectionGene(_innovationIdGenerator.NextId, srcNeuronGeneACBias.InnovationId, tgtNeuronGeneAC.InnovationId, Math.Abs(GenerateRandomConnectionWeight())); connectionGeneList.Add(biasGene); // Register connection with endpoint neurons. srcNeuronGeneACBias.TargetNeurons.Add(biasGene.TargetNodeId); tgtNeuronGeneAC.SourceNeurons.Add(biasGene.SourceNodeId); } double conW = GenerateRandomConnectionWeight(); for (int i = 5; i <= 6; i++) { NeuronGene srcNeuronGeneAC = inputNeuronGeneList[i]; if (!srcNeuronGeneAC.TargetNeurons.Contains(outputNeuronGeneList[2].InnovationId)) { NeuronGene tgtNeuronGeneAC = outputNeuronGeneList[2]; ConnectionGene biasGene = new ConnectionGene(_innovationIdGenerator.NextId, srcNeuronGeneAC.InnovationId, tgtNeuronGeneAC.InnovationId, -Math.Abs(conW)); connectionGeneList.Add(biasGene); // Register connection with endpoint neurons. srcNeuronGeneAC.TargetNeurons.Add(biasGene.TargetNodeId); tgtNeuronGeneAC.SourceNeurons.Add(biasGene.SourceNodeId); } srcNeuronGeneAC = inputNeuronGeneList[i]; if (!srcNeuronGeneAC.TargetNeurons.Contains(outputNeuronGeneList[5].InnovationId)) { NeuronGene tgtNeuronGeneAC = outputNeuronGeneList[5]; ConnectionGene biasGene = new ConnectionGene(_innovationIdGenerator.NextId, srcNeuronGeneAC.InnovationId, tgtNeuronGeneAC.InnovationId, -Math.Abs(conW)); connectionGeneList.Add(biasGene); // Register connection with endpoint neurons. srcNeuronGeneAC.TargetNeurons.Add(biasGene.TargetNodeId); tgtNeuronGeneAC.SourceNeurons.Add(biasGene.SourceNodeId); } } #endregion #region Add connection to bisas connection strength based on distance for (int i = 5; i <= 6; i++) { NeuronGene srcNeuronGeneAC = inputNeuronGeneList[i]; if (!srcNeuronGeneAC.TargetNeurons.Contains(outputNeuronGeneList[0].InnovationId)) { NeuronGene tgtNeuronGeneAC = outputNeuronGeneList[0]; ConnectionGene biasGene = new ConnectionGene(_innovationIdGenerator.NextId, srcNeuronGeneAC.InnovationId, tgtNeuronGeneAC.InnovationId, Math.Abs(GenerateRandomConnectionWeight())); connectionGeneList.Add(biasGene); // Register connection with endpoint neurons. srcNeuronGeneAC.TargetNeurons.Add(biasGene.TargetNodeId); tgtNeuronGeneAC.SourceNeurons.Add(biasGene.SourceNodeId); } } #endregion for (int i = 0; i < connectionCount; i++) { ConnectionDefinition def = connectionDefArr[i]; NeuronGene srcNeuronGene = inputNeuronGeneList[def._sourceNeuronIdx]; NeuronGene tgtNeuronGene = outputNeuronGeneList[def._targetNeuronIdx]; ConnectionGene cGene = new ConnectionGene(def._innovationId, srcNeuronGene.InnovationId, tgtNeuronGene.InnovationId, GenerateRandomConnectionWeight()); if (!srcNeuronGene.TargetNeurons.Contains(cGene.TargetNodeId)) { connectionGeneList.Add(cGene); // Register connection with endpoint neurons. srcNeuronGene.TargetNeurons.Add(cGene.TargetNodeId); tgtNeuronGene.SourceNeurons.Add(cGene.SourceNodeId); } } // Ensure connections are sorted. connectionGeneList.SortByInnovationId(); // Create and return the completed genome object. return CreateGenome(_genomeIdGenerator.NextId, birthGeneration, neuronGeneList, connectionGeneList, _inputNeuronCount, _outputNeuronCount, false); }
// NOTE: Multi-Plane Substrates ARE supported by this method! private NeatGenome.NeatGenome generateHiveBrainGenomeStack(INetwork network, List<float> stackCoordinates, bool normalizeWeights, bool adaptiveNetwork, bool modulatoryNet,bool ct) { //bool relativeCoordinate = false; bool oneWay = false; bool homogeneous = false ; Dictionary<String, float> weights = new Dictionary<String, float>(); float timeConstantMin = 0.1f; float timeConstantMax = 2.0f; uint numberOfAgents = (uint)stackCoordinates.Count; IActivationFunction activationFunction = HyperNEATParameters.substrateActivationFunction; ConnectionGeneList connections = new ConnectionGeneList((int)(numberOfAgents * (InputCount * HiddenCount) + numberOfAgents * (HiddenCount * OutputCount))); // TODO: Perhaps get an exact count of connections in the constructor and use that value here? float[] coordinates = new float[5]; //JUSTIN: Used to be 6 coordinates, zstack was duplicated for relativeCoordinate hyjinx. fixed it. // Inputs to the CPPN: [srcX, srcY, tgX, tgY, zstack] float output; uint connectionCounter = 0; float agentDelta = 2.0f / (numberOfAgents - 1); int iterations = 2 * (network.TotalNeuronCount - (network.InputNeuronCount + network.OutputNeuronCount)) + 1; uint totalOutputCount = OutputCount * numberOfAgents; uint totalInputCount = InputCount * numberOfAgents; uint totalHiddenCount = HiddenCount * numberOfAgents; uint sourceCount, targetCout; double weightRange = HyperNEATParameters.weightRange; double threshold = HyperNEATParameters.threshold; NeuronGeneList neurons; // SharpNEAT requires that the neuron list be in this order: bias|input|output|hidden neurons = new NeuronGeneList((int)(InputCount * numberOfAgents + OutputCount * numberOfAgents + HiddenCount * numberOfAgents)); // set up the input nodes for (uint a = 0; a < totalInputCount; a++) { neurons.Add(new NeuronGene(a, NeuronType.Input, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // set up the output nodes for (uint a = 0; a < totalOutputCount; a++) { neurons.Add(new NeuronGene(a + InputCount * numberOfAgents, NeuronType.Output, activationFunction)); } // set up the hidden nodes for (uint a = 0; a < totalHiddenCount; a++) { neurons.Add(new NeuronGene(a + InputCount * numberOfAgents + OutputCount * numberOfAgents, NeuronType.Hidden, activationFunction)); } uint agent = 0; float A = 0.0f, B = 0.0f, C = 0.0f, D = 0.0f, learningRate = 0.0f, modConnection; // CPPN Outputs: [ Weights ] [ Biases ] // When using multi-plane substrates, there will be multiple Weight and Bias outputs. // There is a Weight output for every plane-to-plane connection (including a plane connected to itself, as in regular substrates) // There is a Bias output for every plane // Since "regular substrates" only have 1 plane, they only have 1 Weight and 1 Bias output. MP substrates have more. :) int numPlanes = planes.Count; int numPlaneConnections = planesConnected.Count; int computedIndex; foreach (float stackCoordinate in stackCoordinates) { coordinates[4] = stackCoordinate; //coordinates[4] = homogeneous ? 0 : stackCoordinate;//-1 ? -1 : 0;//0;//stackCoordinate; //coordinates[5] = stackCoordinate; uint sourceID = uint.MaxValue, targetID = uint.MaxValue; NeuronGroup connectedNG; foreach (NeuronGroup ng in neuronGroups) { foreach (uint connectedTo in ng.ConnectedTo) { /*if (!relativeCoordinate) coordinates[5] = stackCoordinate; else //USE RELATIVE coordinates[5] = 0;//*/ connectedNG = getNeuronGroup(connectedTo); sourceCount = 0; foreach (PointF source in ng.NeuronPositions) { //-----------------Get the bias of the source node /* switch (ng.GroupType) { case 0: sourceID = (agent * InputCount) + ng.GlobalID + sourceCount; break; //Input case 1: sourceID = totalInputCount + (agent * OutputCount) + ng.GlobalID + sourceCount; break; //Output case 2: sourceID = totalInputCount + totalOutputCount + (agent * HiddenCount) + ng.GlobalID + sourceCount; break; //Hidden } coordinates[0] = source.X; coordinates[1] = source.Y; coordinates[2] = 0.0f; coordinates[3] = 0.0f; network.ClearSignals(); network.SetInputSignals(coordinates); network.RecursiveActivation();//network.MultipleSteps(iterations); neurons[(int)sourceID].Bias = (float)(network.GetOutputSignal(1) * weightRange); if (ct) { neurons[(int)sourceID].TimeConstant = 0.01f + ((((float)network.GetOutputSignal(2) + 1.0f) / 2.0f) * .05f); System.Diagnostics.Debug.Assert(neurons[(int)sourceID].TimeConstant > 0); }*/ //---------------------------- targetCout = 0; foreach (PointF target in connectedNG.NeuronPositions) { switch (ng.GroupType) { case 0: sourceID = (agent * InputCount) + ng.GlobalID + sourceCount; break; //Input case 1: sourceID = totalInputCount + (agent * OutputCount) + ng.GlobalID + sourceCount; break; //Output case 2: sourceID = totalInputCount + totalOutputCount + (agent * HiddenCount) + ng.GlobalID + sourceCount; break; //Hidden } switch (connectedNG.GroupType) { case 0: targetID = (agent * InputCount) + connectedNG.GlobalID + targetCout; break; case 1: targetID = totalInputCount + (agent * OutputCount) + connectedNG.GlobalID + targetCout; break; case 2: targetID = totalInputCount + totalOutputCount + (agent * HiddenCount) + connectedNG.GlobalID + targetCout; break; } //-----------------Get the bias of the target node coordinates[0] = target.X; coordinates[1] = target.Y; coordinates[2] = 0.0f; coordinates[3] = 0.0f; //String s = arrayToString(coordinates); //if (weights.ContainsKey(s)) // neurons[(int)targetID].Bias = weights[s]; //else { network.ClearSignals(); network.SetInputSignals(coordinates); network.RecursiveActivation();//network.MultipleSteps(iterations); computedIndex = numPlaneConnections + planes.IndexOf(connectedNG.Plane); //neurons[(int)targetID].Bias = (float)(network.GetOutputSignal(1) * weightRange); neurons[(int)targetID].Bias = (float)(network.GetOutputSignal(computedIndex) * weightRange); //weights.Add(s,neurons[(int)targetID].Bias); } if (ct) { neurons[(int)targetID].TimeConstant = timeConstantMin + ((((float)network.GetOutputSignal(2) + 1.0f) / 2.0f) * (timeConstantMax - timeConstantMin)); System.Diagnostics.Debug.Assert(neurons[(int)targetID].TimeConstant > 0); } //---------------------------- coordinates[0] = source.X; coordinates[1] = source.Y; coordinates[2] = target.X; coordinates[3] = target.Y; //Console.WriteLine(arrayToString(coordinates)); //if(weights.ContainsKey(s)) // output = weights[s]; //else { network.ClearSignals(); network.SetInputSignals(coordinates); network.RecursiveActivation();//network.MultipleSteps(iterations); computedIndex = indexOfPlaneConnection(ng.Plane, connectedNG.Plane); //output = network.GetOutputSignal(0); output = network.GetOutputSignal(computedIndex); //weights.Add(s, output); } double leo = 0.0; if (adaptiveNetwork) { A = network.GetOutputSignal(2); B = network.GetOutputSignal(3); C = network.GetOutputSignal(4); D = network.GetOutputSignal(5); learningRate = network.GetOutputSignal(6); } if (modulatoryNet) { modConnection = network.GetOutputSignal(7); } else { modConnection = 0.0f; } if (useLeo) { threshold = 0.0; leo = network.GetOutputSignal(2); } if (!useLeo || leo > 0.0) if (Math.Abs(output) > threshold) { float weight = (float)(((Math.Abs(output) - (threshold)) / (1 - threshold)) * weightRange * Math.Sign(output)); //if (adaptiveNetwork) //{ // //If adaptive network set weight to small value // weight = 0.1f; //} connections.Add(new ConnectionGene(connectionCounter++, sourceID, targetID, weight, ref coordinates)); } //else //{ // Console.WriteLine("Not connected"); //} targetCout++; } sourceCount++; } } foreach (uint connectedTo in ng.HiveConnectedTo) { bool wrapAround = true; for (uint agentConnect = 0; agentConnect < stackCoordinates.Count; agentConnect++) { //Make sure we're not making a recurrent connection on the same agent //if (agentConnect == agent) // continue; // else if ((agent == stackCoordinates.Count - 1 && agentConnect == 0) || (agent == 0 && agentConnect == stackCoordinates.Count - 1)) // ;//agentConnect = 0; if (agent != 0 && agent != stackCoordinates.Count - 1) continue; //if (agent == 1) // continue; //if (agentConnect != 0 ) // continue; //Limits connections to only neighbors. Good? //if (!((agent == 0 || agentConnect >= agent - 1) && agentConnect <= agent + 1)) // continue; //if (agentConnect > agent + 1 || agentConnect < agent - 1) // continue; if (oneWay) { //ONE-WAY if (agentConnect > agent + 1 || agentConnect < agent) continue; } /*if (!relativeCoordinate) //USE THE Z COORDINATE coordinates[5] = stackCoordinates[(int)agentConnect]; else //USE THE RELATIVE COORDINATE coordinates[5] = agentConnect > agent ? 1 : -1; //*/ //WRAP AROUND /*if (agent == stackCoordinates.Count - 1 && agentConnect == 0) coordinates[5] = 1; else if (agent == 0 && agentConnect == stackCoordinates.Count - 1) coordinates[5] = -1; */ connectedNG = getNeuronGroup(connectedTo); sourceCount = 0; foreach (PointF source in ng.NeuronPositions) { //-----------------Get the bias of the source node /* switch (ng.GroupType) { case 0: sourceID = (agent * InputCount) + ng.GlobalID + sourceCount; break; //Input case 1: sourceID = totalInputCount + (agent * OutputCount) + ng.GlobalID + sourceCount; break; //Output case 2: sourceID = totalInputCount + totalOutputCount + (agent * HiddenCount) + ng.GlobalID + sourceCount; break; //Hidden } coordinates[0] = source.X; coordinates[1] = source.Y; coordinates[2] = 0.0f; coordinates[3] = 0.0f; network.ClearSignals(); network.SetInputSignals(coordinates); network.RecursiveActivation();//network.MultipleSteps(iterations); neurons[(int)sourceID].Bias = (float)(network.GetOutputSignal(1) * weightRange); if (ct) { neurons[(int)sourceID].TimeConstant = 0.01f + ((((float)network.GetOutputSignal(2) + 1.0f) / 2.0f) * .05f); System.Diagnostics.Debug.Assert(neurons[(int)sourceID].TimeConstant > 0); }*/ //---------------------------- targetCout = 0; foreach (PointF target in connectedNG.NeuronPositions) { /*if ((source.X != target.X)) { targetCout++; continue; }*/ if (/*source.X!= target.X ||*/ target.X != coordinates[4])// || source.X!= coordinates[4]) { targetCout++; continue; } /* if (agent != 0 && agent != stackCoordinates.Count - 1) { if(agentConnect != 0 && agentConnect != stackCoordinates.Count - 1) { targetCout++; continue; } }*/ switch (ng.GroupType) { case 0: sourceID = (agent * InputCount) + ng.GlobalID + sourceCount; break; //Input case 1: sourceID = totalInputCount + (agent * OutputCount) + ng.GlobalID + sourceCount; break; //Output case 2: sourceID = totalInputCount + totalOutputCount + (agent * HiddenCount) + ng.GlobalID + sourceCount; break; //Hidden } switch (connectedNG.GroupType) { case 0: targetID = (agentConnect * InputCount) + connectedNG.GlobalID + targetCout; break; case 1: targetID = totalInputCount + (agentConnect * OutputCount) + connectedNG.GlobalID + targetCout; break; case 2: targetID = totalInputCount + totalOutputCount + (agentConnect * HiddenCount) + connectedNG.GlobalID + targetCout; break; } //-----------------Get the bias of the target node coordinates[0] = target.X; coordinates[1] = target.Y; coordinates[2] = 0.0f; coordinates[3] = 0.0f; //String s = arrayToString(coordinates); //if (weights.ContainsKey(s)) // neurons[(int)targetID].Bias = weights[s]; //else { network.ClearSignals(); network.SetInputSignals(coordinates); network.RecursiveActivation();//network.MultipleSteps(iterations); computedIndex = numPlaneConnections + planes.IndexOf(connectedNG.Plane); //neurons[(int)targetID].Bias = (float)(network.GetOutputSignal(1) * weightRange); neurons[(int)targetID].Bias = (float)(network.GetOutputSignal(computedIndex) * weightRange); // weights.Add(s, neurons[(int)targetID].Bias); } if (ct) { neurons[(int)targetID].TimeConstant = timeConstantMin + ((((float)network.GetOutputSignal(2) + 1.0f) / 2.0f) * (timeConstantMax - timeConstantMin)); System.Diagnostics.Debug.Assert(neurons[(int)targetID].TimeConstant > 0); } //---------------------------- coordinates[0] = source.X; coordinates[1] = source.Y; coordinates[2] = target.X; coordinates[3] = target.Y; //s = arrayToString(coordinates); //if (weights.ContainsKey(s)) // output = weights[s]; //else { network.ClearSignals(); network.SetInputSignals(coordinates); network.RecursiveActivation();//network.MultipleSteps(iterations); computedIndex = indexOfPlaneConnection(ng.Plane, connectedNG.Plane); //output = network.GetOutputSignal(0); output = network.GetOutputSignal(computedIndex); // weights.Add(s, output); } double leo = 0.0; if (adaptiveNetwork) { A = network.GetOutputSignal(2); B = network.GetOutputSignal(3); C = network.GetOutputSignal(4); D = network.GetOutputSignal(5); learningRate = network.GetOutputSignal(6); } if (modulatoryNet) { modConnection = network.GetOutputSignal(7); } else { modConnection = 0.0f; } if (useLeo) { threshold = 0.0; leo = network.GetOutputSignal(2); } if (!useLeo || leo > 0.0) if (Math.Abs(output) > threshold) { float weight = (float)(((Math.Abs(output) - (threshold)) / (1 - threshold)) * weightRange * Math.Sign(output)); //if (adaptiveNetwork) //{ // //If adaptive network set weight to small value // weight = 0.1f; //} connections.Add(new ConnectionGene(connectionCounter++, sourceID, targetID, weight, ref coordinates, true)); } //else //{ // Console.WriteLine("Not connected"); //} targetCout++; } sourceCount++; } } } } agent++; } if (normalizeWeights) { normalizeWeightConnections(ref connections, neurons.Count); } SharpNeatLib.NeatGenome.NeatGenome sng = new SharpNeatLib.NeatGenome.NeatGenome(0, neurons, connections, (int)(totalInputCount), (int)(totalOutputCount)); sng.networkAdaptable = adaptiveNetwork; sng.networkModulatory = modulatoryNet; return sng; }
public NeatGenome.NeatGenome generateGenomeStackSituationalPolicy(INetwork network, List<float> stackCoordinates, bool normalizeWeights, bool adaptiveNetwork, bool modulatoryNet, float signal) { // Schrum: For debugging //Console.WriteLine("generateGenomeStackSituationalPolicy:signal=" + signal); //Console.WriteLine("CPPN inputs = " + network.InputNeuronCount); uint numberOfAgents = (uint)stackCoordinates.Count; IActivationFunction activationFunction = HyperNEATParameters.substrateActivationFunction; ConnectionGeneList connections = new ConnectionGeneList((int)(numberOfAgents * (InputCount * HiddenCount) + numberOfAgents * (HiddenCount * OutputCount))); // Schrum: Too many inputs: Only store those that are needed //float[] coordinates = new float[5 + 1]; // <-- Schrum: bit sloppy: frequently results in unused CPPN inputs. Should make more precise float[] coordinates = new float[network.InputNeuronCount]; // Schrum: CPPN tracks how many inputs it needs float output; uint connectionCounter = 0; float agentDelta = 2.0f / (numberOfAgents - 1); int iterations = 2 * (network.TotalNeuronCount - (network.InputNeuronCount + network.OutputNeuronCount)) + 1; uint totalOutputCount = OutputCount * numberOfAgents; uint totalInputCount = InputCount * numberOfAgents; uint totalHiddenCount = HiddenCount * numberOfAgents; uint sourceCount, targetCout; double weightRange = HyperNEATParameters.weightRange; double threshold = HyperNEATParameters.threshold; bool[] biasCalculated = new bool[totalHiddenCount + totalOutputCount+totalInputCount]; // Schrum: If we are inside this function, then we either have a heterogeneous team // of a single agent (not sure why that ended up being the case; odd use of homogeneousTeam). // Therefore, numberOfAgents tells us whether we need to save space for a Z-coordinate, // and whether we are expecting a Situation input. if (numberOfAgents == 1 && coordinates.Length > 4) coordinates[4] = signal; // No Z coord, but save situation else if (coordinates.Length > 5) coordinates[5] = signal; // Both Z coord and situation NeuronGeneList neurons; // SharpNEAT requires that the neuron list be in thisorder: bias|input|output|hidden neurons = new NeuronGeneList((int)(InputCount * numberOfAgents + OutputCount * numberOfAgents + HiddenCount * numberOfAgents)); // set up the input nodes for (uint a = 0; a < totalInputCount; a++) { neurons.Add(new NeuronGene(a, NeuronType.Input, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // set up the output nodes for (uint a = 0; a < totalOutputCount; a++) { neurons.Add(new NeuronGene(a + InputCount * numberOfAgents, NeuronType.Output, activationFunction)); } // set up the hidden nodes for (uint a = 0; a < totalHiddenCount; a++) { neurons.Add(new NeuronGene(a + InputCount * numberOfAgents + OutputCount * numberOfAgents, NeuronType.Hidden, activationFunction)); } uint agent = 0; float A = 0.0f, B = 0.0f, C = 0.0f, D = 0.0f, learningRate = 0.0f, modConnection; foreach (float stackCoordinate in stackCoordinates) { // Schrum: Only include Z-coord as input if there are multiple team members if (numberOfAgents > 1) coordinates[4] = stackCoordinate; // Schrum: z-coord will always be at index 4 // Schrum: Debug //Console.WriteLine("CPPN inputs (first 4 blank): " + string.Join(",", coordinates)); uint sourceID = uint.MaxValue, targetID = uint.MaxValue; NeuronGroup connectedNG; foreach (NeuronGroup ng in neuronGroups) { foreach (uint connectedTo in ng.ConnectedTo) { connectedNG = getNeuronGroup(connectedTo); sourceCount = 0; foreach (PointF source in ng.NeuronPositions) { //---------------------------- targetCout = 0; foreach (PointF target in connectedNG.NeuronPositions) { switch (ng.GroupType) { case 0: sourceID = (agent * InputCount) + ng.GlobalID + sourceCount; break; //Input case 1: sourceID = totalInputCount + (agent * OutputCount) + ng.GlobalID + sourceCount; break; //Output case 2: sourceID = totalInputCount + totalOutputCount + (agent * HiddenCount) + ng.GlobalID + sourceCount; break; //Hidden } switch (connectedNG.GroupType) { case 0: targetID = (agent * InputCount) + connectedNG.GlobalID + targetCout; break; case 1: targetID = totalInputCount + (agent * OutputCount) + connectedNG.GlobalID + targetCout; break; case 2: targetID = totalInputCount + totalOutputCount + (agent * HiddenCount) + connectedNG.GlobalID + targetCout; break; } //--- bias //-----------------Get the bias of the target node if (!biasCalculated[targetID]) { coordinates[0] = 0.0f; coordinates[1] = 0.0f; coordinates[2] = target.X; coordinates[3] = target.Y; network.ClearSignals(); network.SetInputSignals(coordinates); ((ModularNetwork)network).RecursiveActivation(); neurons[(int)targetID].Bias = (float)(network.GetOutputSignal(1) * weightRange); biasCalculated[targetID] = true; } //--bias coordinates[0] = source.X; coordinates[1] = source.Y; coordinates[2] = target.X; coordinates[3] = target.Y; // Schrum: Debug //Console.WriteLine("CPPN inputs: " + string.Join(",", coordinates)); network.ClearSignals(); network.SetInputSignals(coordinates); ((ModularNetwork)network).RecursiveActivation(); //network.MultipleSteps(iterations); output = network.GetOutputSignal(0); double leo = 0.0; // Schrum: Observation: It seems impossible to use both LEO and adaptive networks because of these hardcoded magic numbers if (adaptiveNetwork) { A = network.GetOutputSignal(2); B = network.GetOutputSignal(3); C = network.GetOutputSignal(4); D = network.GetOutputSignal(5); learningRate = network.GetOutputSignal(6); } if (modulatoryNet) { modConnection = network.GetOutputSignal(7); } else { modConnection = 0.0f; } // Schrum: Observation: In long run, might be desirable to use LEO, but incompatible with special preference neuron output if (useLeo) { threshold = 0.0; leo = network.GetOutputSignal(2); } // Schrum: This is a horrible hack, but it gets the job done for now. // The reason this works is that it makes the following assumptions that could easily be broken in the future: // 1) It is assumed that the only reason a CPPN would have 3 outputs per policy is if the third is for preference links // 2) It is assumed that in a substrate with a preference neuron, the y-coord will always be 0.8, and no other neuron will have // that y-coord. //Console.WriteLine("output:" + coordinates[0] + "," + coordinates[1] + ":" + coordinates[2] + "," + coordinates[3]); //Console.WriteLine("network.OutputsPerPolicy == 3" + (network.OutputsPerPolicy == 3)); //Console.WriteLine("target.Y == 0.8" + (target.Y == 0.8f)); if (network.OutputsPerPolicy == 3 && target.Y == 0.8f) { // The output from the link for the preference neuron replaces the standard output. // Because the link weight is defined by a totally different CPPN output, the preference // neuron is more free to behave very differently. output = network.GetOutputSignal(2); //Console.WriteLine("Preference output:" + coordinates[0] + "," + coordinates[1] + ":" + coordinates[2] + "," + coordinates[3]); } if (!useLeo || leo > 0.0) if (Math.Abs(output) > threshold) { float weight = (float)(((Math.Abs(output) - (threshold)) / (1 - threshold)) * weightRange * Math.Sign(output)); //if (adaptiveNetwork) //{ // //If adaptive networkset weight to small value // weight = 0.1f; //} connections.Add(new ConnectionGene(connectionCounter++, sourceID, targetID, weight, ref coordinates, A, B, C, D, modConnection, learningRate)); } //else //{ // Console.WriteLine("Not connected"); //} targetCout++; } sourceCount++; } } } agent++; } if (normalizeWeights) { normalizeWeightConnections(ref connections, neurons.Count); } SharpNeatLib.NeatGenome.NeatGenome sng = new SharpNeatLib.NeatGenome.NeatGenome(0, neurons, connections, (int)(totalInputCount), (int)(totalOutputCount)); sng.networkAdaptable = adaptiveNetwork; sng.networkModulatory = modulatoryNet; // Schrum: Debugging // Looking at the control networks has revealed that the order of details in the substrate // description is important. The layer with the preference neuron has to be defined last // if it is to be the final neuron in the linearly organized output layer. //XmlDocument doc = new XmlDocument(); //SharpNeatLib.NeatGenome.Xml.XmlGenomeWriterStatic.Write(doc, sng); //System.IO.FileInfo oFileInfo = new System.IO.FileInfo("temp.xml"); //doc.Save(oFileInfo.FullName); return sng; }
private NeatGenome.NeatGenome generateHomogeneousGenome(INetwork network, bool normalizeWeights, bool adaptiveNetwork, bool modulatoryNet) { IActivationFunction activationFunction = HyperNEATParameters.substrateActivationFunction; ConnectionGeneList connections = new ConnectionGeneList((int)((InputCount * HiddenCount) + (HiddenCount * OutputCount))); float[] coordinates = new float[4]; float output; uint connectionCounter = 0; int iterations = 2 * (network.TotalNeuronCount - (network.InputNeuronCount + network.OutputNeuronCount)) + 1; uint totalOutputCount = OutputCount; uint totalInputCount = InputCount; uint totalHiddenCount = HiddenCount; uint sourceCount, targetCout; double weightRange = HyperNEATParameters.weightRange; double threshold = HyperNEATParameters.threshold; NeuronGeneList neurons; // SharpNEAT requires that the neuron list be in this order: bias|input|output|hidden neurons = new NeuronGeneList((int)(InputCount + OutputCount + HiddenCount)); // set up the input nodes for (uint a = 0; a < totalInputCount; a++) { neurons.Add(new NeuronGene(a, NeuronType.Input, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // set up the output nodes for (uint a = 0; a < totalOutputCount; a++) { neurons.Add(new NeuronGene(a + InputCount, NeuronType.Output, activationFunction)); } // set up the hidden nodes for (uint a = 0; a < totalHiddenCount; a++) { neurons.Add(new NeuronGene(a + InputCount + OutputCount, NeuronType.Hidden, activationFunction)); } bool[] biasCalculated = new bool[totalHiddenCount + totalOutputCount + totalInputCount]; uint sourceID = uint.MaxValue, targetID = uint.MaxValue; NeuronGroup connectedNG; foreach (NeuronGroup ng in neuronGroups) { foreach (uint connectedTo in ng.ConnectedTo) { connectedNG = getNeuronGroup(connectedTo); sourceCount = 0; foreach (PointF source in ng.NeuronPositions) { targetCout = 0; foreach (PointF target in connectedNG.NeuronPositions) { switch (ng.GroupType) { case 0: sourceID = ng.GlobalID + sourceCount; break; //Input case 1: sourceID = totalInputCount + ng.GlobalID + sourceCount; break; //Output case 2: sourceID = totalInputCount + totalOutputCount + ng.GlobalID + sourceCount; break; //Hidden } switch (connectedNG.GroupType) { case 0: targetID = connectedNG.GlobalID + targetCout; break; case 1: targetID = totalInputCount + connectedNG.GlobalID + targetCout; break; case 2: targetID = totalInputCount + totalOutputCount + connectedNG.GlobalID + targetCout; break; } //calculate bias of target node if (!biasCalculated[targetID]) { coordinates[0] = 0.0f; coordinates[1] = 0.0f; coordinates[2] = target.X; coordinates[3] = target.Y; network.ClearSignals(); network.SetInputSignals(coordinates); ((ModularNetwork)network).RecursiveActivation(); neurons[(int)targetID].Bias = (float)(network.GetOutputSignal(1) * weightRange); biasCalculated[targetID] = true; } coordinates[0] = source.X; coordinates[1] = source.Y; coordinates[2] = target.X; coordinates[3] = target.Y; network.ClearSignals(); network.SetInputSignals(coordinates); ((ModularNetwork)network).RecursiveActivation(); //network.MultipleSteps(iterations); output = network.GetOutputSignal(0); if (Math.Abs(output) > threshold) { float weight = (float)(((Math.Abs(output) - (threshold)) / (1 - threshold)) * weightRange * Math.Sign(output)); connections.Add(new ConnectionGene(connectionCounter++, sourceID, targetID, weight, ref coordinates, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); } //else //{ // Console.WriteLine("Not connected"); //} targetCout++; } sourceCount++; } } } if (normalizeWeights) { normalizeWeightConnections(ref connections, neurons.Count); } NeatGenome.NeatGenome gn = new SharpNeatLib.NeatGenome.NeatGenome(0, neurons, connections, (int)(totalInputCount), (int)(totalOutputCount)); gn.networkAdaptable = adaptiveNetwork; gn.networkModulatory = modulatoryNet; return(gn); }
private NeatGenome.NeatGenome generateHomogeneousGenome(INetwork network, bool normalizeWeights, bool adaptiveNetwork, bool modulatoryNet) { IActivationFunction activationFunction = HyperNEATParameters.substrateActivationFunction; ConnectionGeneList connections = new ConnectionGeneList((int)((InputCount * HiddenCount) + (HiddenCount * OutputCount))); float[] coordinates = new float[4]; float output; uint connectionCounter = 0; int iterations = 2 * (network.TotalNeuronCount - (network.InputNeuronCount + network.OutputNeuronCount)) + 1; uint totalOutputCount = OutputCount; uint totalInputCount = InputCount; uint totalHiddenCount = HiddenCount; uint sourceCount, targetCout; double weightRange = HyperNEATParameters.weightRange; double threshold = HyperNEATParameters.threshold; NeuronGeneList neurons; // SharpNEAT requires that the neuron list be in this order: bias|input|output|hidden neurons = new NeuronGeneList((int)(InputCount + OutputCount + HiddenCount)); // set up the input nodes for (uint a = 0; a < totalInputCount; a++) { neurons.Add(new NeuronGene(a, NeuronType.Input, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // set up the output nodes for (uint a = 0; a < totalOutputCount; a++) { neurons.Add(new NeuronGene(a + InputCount, NeuronType.Output, activationFunction)); } // set up the hidden nodes for (uint a = 0; a < totalHiddenCount; a++) { neurons.Add(new NeuronGene(a + InputCount + OutputCount, NeuronType.Hidden, activationFunction)); } bool[] biasCalculated = new bool[totalHiddenCount + totalOutputCount + totalInputCount]; uint sourceID = uint.MaxValue, targetID = uint.MaxValue; NeuronGroup connectedNG; foreach (NeuronGroup ng in neuronGroups) { foreach (uint connectedTo in ng.ConnectedTo) { connectedNG = getNeuronGroup(connectedTo); sourceCount = 0; foreach (PointF source in ng.NeuronPositions) { targetCout = 0; foreach (PointF target in connectedNG.NeuronPositions) { switch (ng.GroupType) { case 0: sourceID = ng.GlobalID + sourceCount; break; //Input case 1: sourceID = totalInputCount + ng.GlobalID + sourceCount; break; //Output case 2: sourceID = totalInputCount + totalOutputCount + ng.GlobalID + sourceCount; break; //Hidden } switch (connectedNG.GroupType) { case 0: targetID = connectedNG.GlobalID + targetCout; break; case 1: targetID = totalInputCount + connectedNG.GlobalID + targetCout; break; case 2: targetID = totalInputCount + totalOutputCount + connectedNG.GlobalID + targetCout; break; } //calculate bias of target node if (!biasCalculated[targetID]) { coordinates[0] = 0.0f; coordinates[1] = 0.0f; coordinates[2] = target.X; coordinates[3] = target.Y; network.ClearSignals(); network.SetInputSignals(coordinates); ((ModularNetwork)network).RecursiveActivation(); neurons[(int)targetID].Bias = (float)(network.GetOutputSignal(1) * weightRange); biasCalculated[targetID] = true; } coordinates[0] = source.X; coordinates[1] = source.Y; coordinates[2] = target.X; coordinates[3] = target.Y; network.ClearSignals(); network.SetInputSignals(coordinates); ((ModularNetwork)network).RecursiveActivation(); //network.MultipleSteps(iterations); output = network.GetOutputSignal(0); if (Math.Abs(output) > threshold) { float weight = (float)(((Math.Abs(output) - (threshold)) / (1 - threshold)) * weightRange * Math.Sign(output)); connections.Add(new ConnectionGene(connectionCounter++, sourceID, targetID, weight, ref coordinates, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); } //else //{ // Console.WriteLine("Not connected"); //} targetCout++; } sourceCount++; } } } if (normalizeWeights) { normalizeWeightConnections(ref connections, neurons.Count); } NeatGenome.NeatGenome gn = new SharpNeatLib.NeatGenome.NeatGenome(0, neurons, connections, (int)(totalInputCount), (int)(totalOutputCount)); gn.networkAdaptable = adaptiveNetwork; gn.networkModulatory = modulatoryNet; return gn; }
public NeatGenome.NeatGenome generateGenomeStackSituationalPolicy(INetwork network, List <float> stackCoordinates, bool normalizeWeights, bool adaptiveNetwork, bool modulatoryNet, float signal) { // Schrum: For debugging //Console.WriteLine("generateGenomeStackSituationalPolicy:signal=" + signal); //Console.WriteLine("CPPN inputs = " + network.InputNeuronCount); uint numberOfAgents = (uint)stackCoordinates.Count; IActivationFunction activationFunction = HyperNEATParameters.substrateActivationFunction; ConnectionGeneList connections = new ConnectionGeneList((int)(numberOfAgents * (InputCount * HiddenCount) + numberOfAgents * (HiddenCount * OutputCount))); // Schrum: Too many inputs: Only store those that are needed //float[] coordinates = new float[5 + 1]; // <-- Schrum: bit sloppy: frequently results in unused CPPN inputs. Should make more precise float[] coordinates = new float[network.InputNeuronCount]; // Schrum: CPPN tracks how many inputs it needs float output; uint connectionCounter = 0; float agentDelta = 2.0f / (numberOfAgents - 1); int iterations = 2 * (network.TotalNeuronCount - (network.InputNeuronCount + network.OutputNeuronCount)) + 1; uint totalOutputCount = OutputCount * numberOfAgents; uint totalInputCount = InputCount * numberOfAgents; uint totalHiddenCount = HiddenCount * numberOfAgents; uint sourceCount, targetCout; double weightRange = HyperNEATParameters.weightRange; double threshold = HyperNEATParameters.threshold; bool[] biasCalculated = new bool[totalHiddenCount + totalOutputCount + totalInputCount]; // Schrum: If we are inside this function, then we either have a heterogeneous team // of a single agent (not sure why that ended up being the case; odd use of homogeneousTeam). // Therefore, numberOfAgents tells us whether we need to save space for a Z-coordinate, // and whether we are expecting a Situation input. if (numberOfAgents == 1 && coordinates.Length > 4) { coordinates[4] = signal; // No Z coord, but save situation } else if (coordinates.Length > 5) { coordinates[5] = signal; // Both Z coord and situation } NeuronGeneList neurons; // SharpNEAT requires that the neuron list be in thisorder: bias|input|output|hidden neurons = new NeuronGeneList((int)(InputCount * numberOfAgents + OutputCount * numberOfAgents + HiddenCount * numberOfAgents)); // set up the input nodes for (uint a = 0; a < totalInputCount; a++) { neurons.Add(new NeuronGene(a, NeuronType.Input, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // set up the output nodes for (uint a = 0; a < totalOutputCount; a++) { neurons.Add(new NeuronGene(a + InputCount * numberOfAgents, NeuronType.Output, activationFunction)); } // set up the hidden nodes for (uint a = 0; a < totalHiddenCount; a++) { neurons.Add(new NeuronGene(a + InputCount * numberOfAgents + OutputCount * numberOfAgents, NeuronType.Hidden, activationFunction)); } uint agent = 0; float A = 0.0f, B = 0.0f, C = 0.0f, D = 0.0f, learningRate = 0.0f, modConnection; foreach (float stackCoordinate in stackCoordinates) { // Schrum: Only include Z-coord as input if there are multiple team members if (numberOfAgents > 1) { coordinates[4] = stackCoordinate; // Schrum: z-coord will always be at index 4 } // Schrum: Debug //Console.WriteLine("CPPN inputs (first 4 blank): " + string.Join(",", coordinates)); uint sourceID = uint.MaxValue, targetID = uint.MaxValue; NeuronGroup connectedNG; foreach (NeuronGroup ng in neuronGroups) { foreach (uint connectedTo in ng.ConnectedTo) { connectedNG = getNeuronGroup(connectedTo); sourceCount = 0; foreach (PointF source in ng.NeuronPositions) { //---------------------------- targetCout = 0; foreach (PointF target in connectedNG.NeuronPositions) { switch (ng.GroupType) { case 0: sourceID = (agent * InputCount) + ng.GlobalID + sourceCount; break; //Input case 1: sourceID = totalInputCount + (agent * OutputCount) + ng.GlobalID + sourceCount; break; //Output case 2: sourceID = totalInputCount + totalOutputCount + (agent * HiddenCount) + ng.GlobalID + sourceCount; break; //Hidden } switch (connectedNG.GroupType) { case 0: targetID = (agent * InputCount) + connectedNG.GlobalID + targetCout; break; case 1: targetID = totalInputCount + (agent * OutputCount) + connectedNG.GlobalID + targetCout; break; case 2: targetID = totalInputCount + totalOutputCount + (agent * HiddenCount) + connectedNG.GlobalID + targetCout; break; } //--- bias //-----------------Get the bias of the target node if (!biasCalculated[targetID]) { coordinates[0] = 0.0f; coordinates[1] = 0.0f; coordinates[2] = target.X; coordinates[3] = target.Y; network.ClearSignals(); network.SetInputSignals(coordinates); ((ModularNetwork)network).RecursiveActivation(); neurons[(int)targetID].Bias = (float)(network.GetOutputSignal(1) * weightRange); biasCalculated[targetID] = true; } //--bias coordinates[0] = source.X; coordinates[1] = source.Y; coordinates[2] = target.X; coordinates[3] = target.Y; // Schrum: Debug //Console.WriteLine("CPPN inputs: " + string.Join(",", coordinates)); network.ClearSignals(); network.SetInputSignals(coordinates); ((ModularNetwork)network).RecursiveActivation(); //network.MultipleSteps(iterations); output = network.GetOutputSignal(0); double leo = 0.0; // Schrum: Observation: It seems impossible to use both LEO and adaptive networks because of these hardcoded magic numbers if (adaptiveNetwork) { A = network.GetOutputSignal(2); B = network.GetOutputSignal(3); C = network.GetOutputSignal(4); D = network.GetOutputSignal(5); learningRate = network.GetOutputSignal(6); } if (modulatoryNet) { modConnection = network.GetOutputSignal(7); } else { modConnection = 0.0f; } // Schrum: Observation: In long run, might be desirable to use LEO, but incompatible with special preference neuron output if (useLeo) { threshold = 0.0; leo = network.GetOutputSignal(2); } // Schrum: This is a horrible hack, but it gets the job done for now. // The reason this works is that it makes the following assumptions that could easily be broken in the future: // 1) It is assumed that the only reason a CPPN would have 3 outputs per policy is if the third is for preference links // 2) It is assumed that in a substrate with a preference neuron, the y-coord will always be 0.8, and no other neuron will have // that y-coord. //Console.WriteLine("output:" + coordinates[0] + "," + coordinates[1] + ":" + coordinates[2] + "," + coordinates[3]); //Console.WriteLine("network.OutputsPerPolicy == 3" + (network.OutputsPerPolicy == 3)); //Console.WriteLine("target.Y == 0.8" + (target.Y == 0.8f)); if (network.OutputsPerPolicy == 3 && target.Y == 0.8f) { // The output from the link for the preference neuron replaces the standard output. // Because the link weight is defined by a totally different CPPN output, the preference // neuron is more free to behave very differently. output = network.GetOutputSignal(2); //Console.WriteLine("Preference output:" + coordinates[0] + "," + coordinates[1] + ":" + coordinates[2] + "," + coordinates[3]); } if (!useLeo || leo > 0.0) { if (Math.Abs(output) > threshold) { float weight = (float)(((Math.Abs(output) - (threshold)) / (1 - threshold)) * weightRange * Math.Sign(output)); //if (adaptiveNetwork) //{ // //If adaptive networkset weight to small value // weight = 0.1f; //} connections.Add(new ConnectionGene(connectionCounter++, sourceID, targetID, weight, ref coordinates, A, B, C, D, modConnection, learningRate)); } } //else //{ // Console.WriteLine("Not connected"); //} targetCout++; } sourceCount++; } } } agent++; } if (normalizeWeights) { normalizeWeightConnections(ref connections, neurons.Count); } SharpNeatLib.NeatGenome.NeatGenome sng = new SharpNeatLib.NeatGenome.NeatGenome(0, neurons, connections, (int)(totalInputCount), (int)(totalOutputCount)); sng.networkAdaptable = adaptiveNetwork; sng.networkModulatory = modulatoryNet; // Schrum: Debugging // Looking at the control networks has revealed that the order of details in the substrate // description is important. The layer with the preference neuron has to be defined last // if it is to be the final neuron in the linearly organized output layer. //XmlDocument doc = new XmlDocument(); //SharpNeatLib.NeatGenome.Xml.XmlGenomeWriterStatic.Write(doc, sng); //System.IO.FileInfo oFileInfo = new System.IO.FileInfo("temp.xml"); //doc.Save(oFileInfo.FullName); return(sng); }
/// <summary> /// Creates a single randomly initialised genome. /// A random set of connections are made form the input to the output neurons, the number of /// connections made is based on the NeatGenomeParameters.InitialInterconnectionsProportion /// which specifies the proportion of all posssible input-output connections to be made in /// initial genomes. /// The connections that are made are allocated innovation IDs in a consistent manner across /// the initial population of genomes. To do this we allocate IDs sequentially to all possible /// interconnections and then randomly select some proportion of connections for inclusion in the /// genome. In addition, for this scheme to work the innovation ID generator must be reset to zero /// prior to each call to CreateGenome(), and a test is made to ensure this is the case. /// The consistent allocation of innovation IDs ensure that equivalent connections in different /// genomes have the same innovation ID, and although this isn't strictly necessary it is /// required for sexual reproduction to work effectively - like structures are detected by comparing /// innovation IDs only. /// </summary> /// <param name="birthGeneration"> /// The current evolution algorithm generation. /// Assigned to the new genome as its birth generation. /// </param> public override NeatGenome CreateGenome(uint birthGeneration) { NeuronGeneList neuronGeneList = new NeuronGeneList(_inputNeuronCount + _outputNeuronCount + _hiddenNeuronCount); NeuronGeneList inputNeuronGeneList = new NeuronGeneList(_inputNeuronCount); // includes single bias neuron. NeuronGeneList outputNeuronGeneList = new NeuronGeneList(_outputNeuronCount); NeuronGeneList hiddenNeuronGeneList = new NeuronGeneList(_hiddenNeuronCount); // Create a single bias neuron. uint biasNeuronId = _innovationIdGenerator.NextId; if (0 != biasNeuronId) { // The ID generator must be reset before calling this method so that all generated genomes use the // same innovation ID for matching neurons and structures. throw new SharpNeatException("IdGenerator must be reset before calling CreateGenome(uint)"); } // Note. Genes within nGeneList must always be arranged according to the following layout plan. // Bias - single neuron. Innovation ID = 0 // Input neurons. // Output neurons. // Hidden neurons. NeuronGene neuronGene = CreateNeuronGene(biasNeuronId, NodeType.Bias); inputNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); // Create input neuron genes. for (int i = 0; i < _inputNeuronCount; i++) { neuronGene = CreateNeuronGene(_innovationIdGenerator.NextId, NodeType.Input); inputNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); } // Create output neuron genes. for (int i = 0; i < _outputNeuronCount; i++) { neuronGene = CreateNeuronGene(_innovationIdGenerator.NextId, NodeType.Output); outputNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); } // Create hidden neuron genes. for (int i = 0; i < _hiddenNeuronCount; i++) { neuronGene = CreateNeuronGene(_innovationIdGenerator.NextId, NodeType.Hidden); hiddenNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); } // Define all possible connections between the input and hidden neurons and the hidden and output neurons // (fully interconnected with minimal hidden/feature layer). int srcCount = inputNeuronGeneList.Count; int tgtCount = outputNeuronGeneList.Count; int hdnCount = hiddenNeuronGeneList.Count; ConnectionDefinition[] srcHdnConnectionDefArr = new ConnectionDefinition[srcCount * hdnCount]; ConnectionDefinition[] hdnTgtConnectionDefArr = new ConnectionDefinition[tgtCount * hdnCount]; for (int hdnIdx = 0, i = 0; hdnIdx < hdnCount; hdnIdx++) { for (int srcIdx = 0; srcIdx < srcCount; srcIdx++) { srcHdnConnectionDefArr[i++] = new ConnectionDefinition(_innovationIdGenerator.NextId, srcIdx, hdnIdx); } } for (int hdnIdx = 0, i = 0; hdnIdx < hdnCount; hdnIdx++) { for (int tgtIdx = 0; tgtIdx < tgtCount; tgtIdx++) { hdnTgtConnectionDefArr[i++] = new ConnectionDefinition(_innovationIdGenerator.NextId, hdnIdx, tgtIdx); } } // Shuffle the array of possible connections. Utilities.Shuffle(srcHdnConnectionDefArr, _rng); Utilities.Shuffle(hdnTgtConnectionDefArr, _rng); // Select connection definitions from the head of the list and convert them to real connections. // We want some proportion of all possible connections but at least one (Connectionless genomes are not allowed). int srcConnectionCount = (int) Utilities.ProbabilisticRound( srcHdnConnectionDefArr.Length*_neatGenomeParamsComplexifying.InitialInterconnectionsProportion, _rng); srcConnectionCount = Math.Max(1, srcConnectionCount); int tgtConnectionCount = (int)Utilities.ProbabilisticRound( hdnTgtConnectionDefArr.Length * _neatGenomeParamsComplexifying.InitialInterconnectionsProportion, _rng); tgtConnectionCount = Math.Max(1, tgtConnectionCount); // Create the connection gene list and populate it. ConnectionGeneList connectionGeneList = new ConnectionGeneList(srcConnectionCount + tgtConnectionCount); for (int i = 0; i < srcConnectionCount; i++) { ConnectionDefinition def = srcHdnConnectionDefArr[i]; NeuronGene srcNeuronGene = inputNeuronGeneList[def._sourceNeuronIdx]; NeuronGene tgtNeuronGene = hiddenNeuronGeneList[def._targetNeuronIdx]; ConnectionGene cGene = new ConnectionGene(def._innovationId, srcNeuronGene.InnovationId, tgtNeuronGene.InnovationId, GenerateRandomConnectionWeight()); connectionGeneList.Add(cGene); // Register connection with endpoint neurons. srcNeuronGene.TargetNeurons.Add(cGene.TargetNodeId); tgtNeuronGene.SourceNeurons.Add(cGene.SourceNodeId); } for (int i = 0; i < tgtConnectionCount; i++) { ConnectionDefinition def = hdnTgtConnectionDefArr[i]; NeuronGene srcNeuronGene = hiddenNeuronGeneList[def._sourceNeuronIdx]; NeuronGene tgtNeuronGene = outputNeuronGeneList[def._targetNeuronIdx]; ConnectionGene cGene = new ConnectionGene(def._innovationId, srcNeuronGene.InnovationId, tgtNeuronGene.InnovationId, GenerateRandomConnectionWeight()); connectionGeneList.Add(cGene); // Register connection with endpoint neurons. srcNeuronGene.TargetNeurons.Add(cGene.TargetNodeId); tgtNeuronGene.SourceNeurons.Add(cGene.SourceNodeId); } // Ensure connections are sorted. connectionGeneList.SortByInnovationId(); // Create and return the completed genome object. return CreateGenome(_genomeIdGenerator.NextId, birthGeneration, neuronGeneList, connectionGeneList, _inputNeuronCount, _outputNeuronCount, false); }
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); }
// MPS NOT supported by this method private NeatGenome.NeatGenome generateMultiGenomeStackES(INetwork network, List<float> stackCoordinates, bool normalizeWeights, bool adaptiveNetwork, bool modulatoryNet) { if (useMultiPlaneSubstrate) throw new Exception("MPS not implemented for these parameters"); uint numberOfAgents = (uint)stackCoordinates.Count; IActivationFunction activationFunction = HyperNEATParameters.substrateActivationFunction; ConnectionGeneList connections = new ConnectionGeneList((int)(numberOfAgents * (InputCount * HiddenCount) + numberOfAgents * (HiddenCount * OutputCount))); float[] coordinates = new float[5]; float output; uint connectionCounter = 0; float agentDelta = 2.0f / (numberOfAgents - 1); int iterations = 2 * (network.TotalNeuronCount - (network.InputNeuronCount + network.OutputNeuronCount)) + 1; uint totalOutputCount = OutputCount * numberOfAgents; uint totalInputCount = InputCount * numberOfAgents; uint totalHiddenCount = HiddenCount * numberOfAgents; uint sourceCount, targetCout; double weightRange = HyperNEATParameters.weightRange; double threshold = HyperNEATParameters.threshold; NeuronGeneList neurons; // SharpNEAT requires that the neuron list be in this order: bias|input|output|hidden neurons = new NeuronGeneList((int)(InputCount * numberOfAgents + OutputCount * numberOfAgents + HiddenCount * numberOfAgents)); // set up the input nodes for (uint a = 0; a < totalInputCount; a++) { neurons.Add(new NeuronGene(a, NeuronType.Input, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // set up the output nodes for (uint a = 0; a < totalOutputCount; a++) { neurons.Add(new NeuronGene(a + InputCount * numberOfAgents, NeuronType.Output, activationFunction)); } uint agent = 0; float A = 0.0f, B = 0.0f, C = 0.0f, D = 0.0f, learningRate = 0.0f, modConnection; List<PointF> outputNeuronPositions = getNeuronGroupByType(1); List<PointF> inputNeuronPositions = getNeuronGroupByType(0); uint hiddenCount = 0; foreach (float stackCoordinate in stackCoordinates) { List<PointF> hiddenNeuronPositions = new List<PointF>(); ConnectionGeneList con = new ConnectionGeneList(); SubstrateEvolution se = new SubstrateEvolution(); se.generateConnections(inputNeuronPositions, outputNeuronPositions, network, SubstrateEvolution.SAMPLE_WIDTH, SubstrateEvolution.SAMPLE_TRESHOLD, SubstrateEvolution.NEIGHBOR_LEVEL, SubstrateEvolution.INCREASE_RESSOLUTION_THRESHOLD, SubstrateEvolution.MIN_DISTANCE, SubstrateEvolution.CONNECTION_TRESHOLD, //0.4. ConnectionThreshold InputCount, OutputCount, -1.0f, -1.0f, 1.0f, 1.0f, ref con, ref hiddenNeuronPositions, stackCoordinate); // set up the hidden nodes for (uint a = 0; a < hiddenNeuronPositions.Count; a++) { neurons.Add(new NeuronGene(hiddenCount + a + totalInputCount + totalOutputCount, NeuronType.Hidden, activationFunction)); } foreach (ConnectionGene c in con) { if (c.SourceNeuronId < InputCount) { c.SourceNeuronId += agent * InputCount; } else if (c.SourceNeuronId < InputCount + OutputCount) { c.SourceNeuronId = (c.SourceNeuronId - InputCount) + totalInputCount + agent * OutputCount; } else { c.SourceNeuronId = (uint)((c.SourceNeuronId - InputCount - OutputCount) + totalInputCount + totalOutputCount + hiddenCount); } if (c.TargetNeuronId < InputCount) { c.TargetNeuronId += agent * InputCount; } else if (c.TargetNeuronId < InputCount + OutputCount) { c.TargetNeuronId = (c.TargetNeuronId - InputCount) + totalInputCount + agent * OutputCount; } else { c.TargetNeuronId = (uint)((c.TargetNeuronId - InputCount - OutputCount) + totalInputCount + totalOutputCount + hiddenCount); } connections.Add(new ConnectionGene(connectionCounter++, c.SourceNeuronId, c.TargetNeuronId, c.Weight, ref c.coordinates)); } hiddenCount += (uint)hiddenNeuronPositions.Count; agent++; } if (normalizeWeights) { normalizeWeightConnections(ref connections, neurons.Count); } SharpNeatLib.NeatGenome.NeatGenome sng = new SharpNeatLib.NeatGenome.NeatGenome(0, neurons, connections, (int)(totalInputCount), (int)(totalOutputCount)); sng.networkAdaptable = adaptiveNetwork; sng.networkModulatory = modulatoryNet; return sng; }
//public static public static NeatGenome Read(XmlElement xmlGenome) { int inputNeuronCount = 0; int outputNeuronCount = 0; uint id = uint.Parse(XmlUtilities.GetAttributeValue(xmlGenome, "id")); //--- Read neuron genes into a list. NeuronGeneList neuronGeneList = new NeuronGeneList(); XmlNodeList listNeuronGenes = xmlGenome.SelectNodes("neurons/neuron"); foreach (XmlElement xmlNeuronGene in listNeuronGenes) { NeuronGene neuronGene = ReadNeuronGene(xmlNeuronGene); // Count the input and output neurons as we go. switch (neuronGene.NeuronType) { case NeuronType.Input: inputNeuronCount++; break; case NeuronType.Output: outputNeuronCount++; break; } neuronGeneList.Add(neuronGene); } //--- Read module genes into a list. List <ModuleGene> moduleGeneList = new List <ModuleGene>(); XmlNodeList listModuleGenes = xmlGenome.SelectNodes("modules/module"); foreach (XmlElement xmlModuleGene in listModuleGenes) { moduleGeneList.Add(ReadModuleGene(xmlModuleGene)); } //--- Read connection genes into a list. ConnectionGeneList connectionGeneList = new ConnectionGeneList(); XmlNodeList listConnectionGenes = xmlGenome.SelectNodes("connections/connection"); foreach (XmlElement xmlConnectionGene in listConnectionGenes) { connectionGeneList.Add(ReadConnectionGene(xmlConnectionGene)); } // Read behavior list NeatGenome g = new NeatGenome(id, neuronGeneList, moduleGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount); XmlNode behaviorNode = xmlGenome.SelectSingleNode("behavior"); if (behaviorNode != null) { g.Behavior = ReadBehavior(behaviorNode); //TODO bug is here g.Behavior.objectives = new double[6]; g.objectives = new double[6]; } /* * XmlNode behaviorNode = xmlGenome.SelectSingleNode("behavior"); * if (behaviorNode != null) * { * g.Behavior = ReadBehavior(behaviorNode.SelectSingleNode("list")); //TODO bug is here * g.Behavior.objectives = new double[6]; * g.objectives = new double[6]; * } */ return(g); }
// MPS NOT supported by this method private NeatGenome.NeatGenome generateHomogeneousGenomeES(INetwork network, bool normalizeWeights, bool adaptiveNetwork, bool modulatoryNet) { if (useMultiPlaneSubstrate) throw new Exception("MPS not implemented for these parameters"); //CHECK TO SEE IF HIDDEN NEURONS ARE OUTPUT NEURONS List<PointF> hiddenNeuronPositions = new List<PointF>(); IActivationFunction activationFunction = HyperNEATParameters.substrateActivationFunction; ConnectionGeneList connections = new ConnectionGeneList();//(int)((InputCount * HiddenCount) + (HiddenCount * OutputCount))); List<PointF> outputNeuronPositions = getNeuronGroupByType(1); List<PointF> inputNeuronPositions = getNeuronGroupByType(0); SubstrateEvolution se = new SubstrateEvolution(); se.generateConnections(inputNeuronPositions, outputNeuronPositions, network, SubstrateEvolution.SAMPLE_WIDTH, SubstrateEvolution.SAMPLE_TRESHOLD, SubstrateEvolution.NEIGHBOR_LEVEL, SubstrateEvolution.INCREASE_RESSOLUTION_THRESHOLD, SubstrateEvolution.MIN_DISTANCE, SubstrateEvolution.CONNECTION_TRESHOLD, //0.4. ConnectionThreshold InputCount, OutputCount, -1.0f, -1.0f, 1.0f, 1.0f, ref connections, ref hiddenNeuronPositions); HiddenCount = (uint)hiddenNeuronPositions.Count; float[] coordinates = new float[5]; uint connectionCounter = (uint)connections.Count; NeuronGeneList neurons; // SharpNEAT requires that the neuron list be in this order: bias|input|output|hidden neurons = new NeuronGeneList((int)(InputCount + OutputCount + HiddenCount)); // set up the input nodes for (uint a = 0; a < InputCount; a++) { neurons.Add(new NeuronGene(a, NeuronType.Input, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // set up the output nodes for (uint a = 0; a < OutputCount; a++) { neurons.Add(new NeuronGene(a + InputCount, NeuronType.Output, activationFunction)); } // set up the hidden nodes for (uint a = 0; a < HiddenCount; a++) { neurons.Add(new NeuronGene(a + InputCount + OutputCount, NeuronType.Hidden, activationFunction)); } uint sourceID = uint.MaxValue, targetID = uint.MaxValue; NeuronGroup connectedNG; uint c1, c2; float delta = 0.15f;//2.0f / InputCount; float minDistance, dist, sourceX = -1, sourceY = -1, targetX = -1, targetY = -1; uint closestNodeIndex; // int index, hiddenCount; //Connections to input nodes // hiddenCount = 0; //TEST?????????????????????????????? double tolerance = 0.1; //bool[] taken = new bool[hiddenNeuronGroup.NeuronPositions.Count]; closestNodeIndex = 0; int ccc; //CONNECT FROM INPUT NODES // ConnectionGeneList addConnections = new ConnectionGeneList(); targetID = 0; bool[] visited = new bool[neurons.Count]; List<uint> nodeList = new List<uint>(); bool[] connectedToInput = new bool[neurons.Count]; //From hidden to output //taken = new bool[hiddenNeuronGroup.NeuronPositions.Count]; // float targetX=-1.0f, targetY=-1.0f; targetID = 0; // bool outputConnectedToInput; bool[] isOutput = new bool[neurons.Count]; //float output, weight; //bool[] connectedToInput = new bool[neurons.Count]; //bool connectToHidden; float totalConnectionDist = 0.0f; //Add connections between Hidden Neurons // addConnections.AddRange(connections); bool danglingConnection = true; while (danglingConnection) { bool[] hasIncomming = new bool[neurons.Count]; foreach (ConnectionGene co in connections) { // if (co.SourceNeuronId != co.TargetNeuronId) // { hasIncomming[co.TargetNeuronId] = true; // } } for (int i = 0; i < InputCount; i++) hasIncomming[i] = true; bool[] hasOutgoing = new bool[neurons.Count]; foreach (ConnectionGene co in connections) { // if (co.TargetNeuronId != co.SourceNeuronId) // { if (co.TargetNeuronId != co.SourceNeuronId) //neurons that only connect to themselfs don't count { hasOutgoing[co.SourceNeuronId] = true; } // } } //Keep output neurons for (int i = 0; i < OutputCount; i++) hasOutgoing[i + InputCount] = true; danglingConnection = false; //Check if there are still dangling connections foreach (ConnectionGene co in connections) { if (!hasOutgoing[co.TargetNeuronId] || !hasIncomming[co.SourceNeuronId]) { danglingConnection = true; break; } } connections.RemoveAll(delegate(ConnectionGene m) { return (!hasIncomming[m.SourceNeuronId]); }); connections.RemoveAll(delegate(ConnectionGene m) { return (!hasOutgoing[m.TargetNeuronId]); }); } if (normalizeWeights) { normalizeWeightConnections(ref connections, neurons.Count); } SharpNeatLib.NeatGenome.NeatGenome gn = new SharpNeatLib.NeatGenome.NeatGenome(0, neurons, connections, (int)(InputCount), (int)(OutputCount)); // SharpNeatLib.NeatGenome.NeatGenome sng = new SharpNeatLib.NeatGenome.NeatGenome(0, neurons, connections, (int)(totalInputCount), (int)(totalOutputCount)); gn.networkAdaptable = adaptiveNetwork; gn.networkModulatory = modulatoryNet; return gn; }
public NeatGenome.NeatGenome generateMultiGenomeStack(INetwork network, List<float> stackCoordinates, bool normalizeWeights, bool adaptiveNetwork, bool modulatoryNet, bool dirComm) { uint numberOfAgents = (uint)stackCoordinates.Count; IActivationFunction activationFunction = HyperNEATParameters.substrateActivationFunction; ConnectionGeneList connections = new ConnectionGeneList((int)(numberOfAgents * (InputCount * HiddenCount) + numberOfAgents * (HiddenCount * OutputCount) + numberOfAgents * (ReceiveCount * HiddenCount) + numberOfAgents * (HiddenCount * TransCount))); float[] coordinates = new float[5]; float output; uint connectionCounter = 0; float agentDelta = 2.0f / (numberOfAgents - 1); int iterations = 2 * (network.TotalNeuronCount - (network.InputNeuronCount + network.OutputNeuronCount)) + 1; uint totalOutputCount = OutputCount * numberOfAgents; uint totalInputCount = InputCount * numberOfAgents; uint totalHiddenCount = HiddenCount * numberOfAgents; uint totalTransCount = TransCount * numberOfAgents; uint totalReceiveCount = ReceiveCount * numberOfAgents; uint sourceCount, targetCout; double weightRange = HyperNEATParameters.weightRange; double threshold = HyperNEATParameters.threshold; NeuronGeneList neurons; // SharpNEAT requires that the neuron list be in this order: bias|input|output|hidden|receive|transmit neurons = new NeuronGeneList((int)(InputCount * numberOfAgents + OutputCount * numberOfAgents + HiddenCount * numberOfAgents + ReceiveCount * numberOfAgents + TransCount * numberOfAgents)); // set up the input nodes for (uint a = 0; a < totalInputCount; a++) { neurons.Add(new NeuronGene(a, NeuronType.Input, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // set up the output nodes for (uint a = 0; a < totalOutputCount; a++) { neurons.Add(new NeuronGene(a + InputCount * numberOfAgents, NeuronType.Output, activationFunction)); } // set up the hidden nodes for (uint a = 0; a < totalHiddenCount; a++) { neurons.Add(new NeuronGene(a + InputCount * numberOfAgents + OutputCount * numberOfAgents, NeuronType.Hidden, activationFunction)); } // set up the receive nodes for (uint a = 0; a < totalReceiveCount; a++) { neurons.Add(new NeuronGene(a + InputCount * numberOfAgents + OutputCount * numberOfAgents + HiddenCount * numberOfAgents, NeuronType.Receive, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // set up the transmit nodes for (uint a = 0; a < totalTransCount; a++) { neurons.Add(new NeuronGene(a + InputCount * numberOfAgents + OutputCount * numberOfAgents + HiddenCount * numberOfAgents + ReceiveCount * numberOfAgents, NeuronType.Transmit, activationFunction)); } bool[] biasCalculated = new bool[totalHiddenCount + totalOutputCount + totalInputCount + totalReceiveCount + totalTransCount]; uint agent = 0; float A = 0.0f, B = 0.0f, C = 0.0f, D = 0.0f, learningRate = 0.0f, modConnection; foreach (float stackCoordinate in stackCoordinates) { coordinates[4] = stackCoordinate; uint sourceID = uint.MaxValue, targetID = uint.MaxValue; NeuronGroup connectedNG; foreach (NeuronGroup ng in neuronGroups) { foreach (uint connectedTo in ng.ConnectedTo) { connectedNG = getNeuronGroup(connectedTo); sourceCount = 0; foreach (PointF source in ng.NeuronPositions) { targetCout = 0; foreach (PointF target in connectedNG.NeuronPositions) { switch (ng.GroupType) { case 0: sourceID = (agent * InputCount) + ng.GlobalID + sourceCount; break; //Input case 1: sourceID = totalInputCount + (agent * OutputCount) + ng.GlobalID + sourceCount; break; //Output case 2: sourceID = totalInputCount + totalOutputCount + (agent * HiddenCount) + ng.GlobalID + sourceCount; break; //Hidden case 3: sourceID = totalInputCount + totalOutputCount + totalHiddenCount + (agent * ReceiveCount) + ng.GlobalID + sourceCount; break; //Receive case 4: sourceID = totalInputCount + totalOutputCount + totalHiddenCount + totalReceiveCount + (agent * TransCount) + ng.GlobalID + sourceCount; break; //Transmit } switch (connectedNG.GroupType) { case 0: targetID = (agent * InputCount) + connectedNG.GlobalID + targetCout; break; case 1: targetID = totalInputCount + (agent * OutputCount) + connectedNG.GlobalID + targetCout; break; case 2: targetID = totalInputCount + totalOutputCount + (agent * HiddenCount) + connectedNG.GlobalID + targetCout; break; case 3: targetID = totalInputCount + totalOutputCount + totalHiddenCount + (agent * ReceiveCount) + connectedNG.GlobalID + targetCout; break; case 4: targetID = totalInputCount + totalOutputCount + totalHiddenCount + totalReceiveCount + (agent * TransCount) + connectedNG.GlobalID + targetCout; break; } //target node bias if (!biasCalculated[targetID]) { coordinates[0] = 0.0f; coordinates[1] = 0.0f; coordinates[2] = target.X; coordinates[3] = target.Y; network.ClearSignals(); network.SetInputSignals(coordinates); ((ModularNetwork)network).RecursiveActivation(); neurons[(int)targetID].Bias = (float)(network.GetOutputSignal(1) * weightRange); biasCalculated[targetID] = true; } coordinates[0] = source.X; coordinates[1] = source.Y; coordinates[2] = target.X; coordinates[3] = target.Y; network.ClearSignals(); network.SetInputSignals(coordinates); ((ModularNetwork)network).RecursiveActivation(); //network.MultipleSteps(iterations); output = network.GetOutputSignal(0); double leo = 0.0; if (adaptiveNetwork) { A = network.GetOutputSignal(2); B = network.GetOutputSignal(3); C = network.GetOutputSignal(4); D = network.GetOutputSignal(5); learningRate = network.GetOutputSignal(6); } if (modulatoryNet) { modConnection = network.GetOutputSignal(7); } else { modConnection = 0.0f; } if (useLeo) { threshold = 0.0; leo = network.GetOutputSignal(2); } if (!useLeo || leo > 0.0) if (Math.Abs(output) > threshold) { float weight = (float)(((Math.Abs(output) - (threshold)) / (1 - threshold)) * weightRange * Math.Sign(output)); //if (adaptiveNetwork) //{ // //If adaptive network set weight to small value // weight = 0.1f; //} connections.Add(new ConnectionGene(connectionCounter++, sourceID, targetID, weight, ref coordinates, A, B, C, D, modConnection, learningRate)); } //else //{ // Console.WriteLine("Not connected"); //} targetCout++; } sourceCount++; } } } agent++; } if (normalizeWeights) { normalizeWeightConnections(ref connections, neurons.Count); } //Add Direct Communication connections if (dirComm) { uint numConnected = ReceiveCount / TransCount; agent = 0; foreach (float stackCoordinate in stackCoordinates) { SortedList<float, uint> closestAgents = new SortedList<float, uint>(); uint i = 0; foreach (float otherCoordinate in stackCoordinates) { if (i == agent) continue; float delta = Math.Abs(stackCoordinate - otherCoordinate); closestAgents.Add(delta, i); i++; } uint[] orderedAgents = new uint[numberOfAgents]; closestAgents.Values.CopyTo(orderedAgents, 0); uint[] connectedAgents = new uint[numConnected]; for (uint j = 0; j < numConnected; j++) { connectedAgents[j] = orderedAgents[j]; } foreach (NeuronGroup ng in neuronGroups) { if (ng.GroupType != 4) continue; sourceCount = 0; foreach (PointF source in ng.NeuronPositions) { uint sourceID = totalInputCount + totalOutputCount + totalHiddenCount + totalReceiveCount + (agent * TransCount) + ng.GlobalID + sourceCount; foreach (uint connectedAgent in connectedAgents) { uint targetID = totalInputCount + totalOutputCount + totalHiddenCount + (connectedAgent * ReceiveCount) + (ng.GlobalID * numConnected) + agent; connections.Add(new ConnectionGene(connectionCounter++, sourceID, targetID, 1.0)); } sourceCount++; } } agent++; } } SharpNeatLib.NeatGenome.NeatGenome sng = new SharpNeatLib.NeatGenome.NeatGenome(0, neurons, connections, (int)(totalInputCount), (int)(totalOutputCount)); sng.networkAdaptable = adaptiveNetwork; sng.networkModulatory = modulatoryNet; return sng; }
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); }
private NeatGenome.NeatGenome generateHomogeneousGenomeES(INetwork network, bool normalizeWeights, bool adaptiveNetwork, bool modulatoryNet) { List<PointF> hiddenNeuronPositions = new List<PointF>(); IActivationFunction activationFunction = HyperNEATParameters.substrateActivationFunction; ConnectionGeneList connections = new ConnectionGeneList();//(int)((InputCount * HiddenCount) + (HiddenCount * OutputCount))); List<PointF> outputNeuronPositions = getNeuronGroupByType(1); List<PointF> inputNeuronPositions = getNeuronGroupByType(0); EvolvableSubstrate se = new EvolvableSubstrate(); se.generateConnections(inputNeuronPositions, outputNeuronPositions, network, HyperNEATParameters.initialRes, (float)HyperNEATParameters.varianceThreshold, (float)HyperNEATParameters.bandingThreshold, (int)HyperNEATParameters.ESIterations, (float)HyperNEATParameters.divisionThreshold, HyperNEATParameters.maximumRes, InputCount, OutputCount, -1.0f, -1.0f, 1.0f, 1.0f, ref connections, ref hiddenNeuronPositions); HiddenCount = (uint)hiddenNeuronPositions.Count; float[] coordinates = new float[5]; uint connectionCounter = (uint)connections.Count; NeuronGeneList neurons; // SharpNEAT requires that the neuron list be in this order: bias|input|output|hidden neurons = new NeuronGeneList((int)(InputCount + OutputCount + HiddenCount)); // set up the input nodes for (uint a = 0; a < InputCount; a++) { neurons.Add(new NeuronGene(a, NeuronType.Input, ActivationFunctionFactory.GetActivationFunction("NullFn"))); } // set up the output nodes for (uint a = 0; a < OutputCount; a++) { neurons.Add(new NeuronGene(a + InputCount, NeuronType.Output, activationFunction)); } // set up the hidden nodes for (uint a = 0; a < HiddenCount; a++) { neurons.Add(new NeuronGene(a + InputCount + OutputCount, NeuronType.Hidden, activationFunction)); } bool[] visited = new bool[neurons.Count]; List<uint> nodeList = new List<uint>(); bool[] connectedToInput = new bool[neurons.Count]; bool[] isOutput = new bool[neurons.Count]; bool danglingConnection = true; while (danglingConnection) { bool[] hasIncomming = new bool[neurons.Count]; foreach (ConnectionGene co in connections) { // if (co.SourceNeuronId != co.TargetNeuronId) // { hasIncomming[co.TargetNeuronId] = true; // } } for (int i = 0; i < InputCount; i++) hasIncomming[i] = true; bool[] hasOutgoing = new bool[neurons.Count]; foreach (ConnectionGene co in connections) { // if (co.TargetNeuronId != co.SourceNeuronId) // { if (co.TargetNeuronId != co.SourceNeuronId) //neurons that only connect to themselfs don't count { hasOutgoing[co.SourceNeuronId] = true; } // } } //Keep output neurons for (int i = 0; i < OutputCount; i++) hasOutgoing[i + InputCount] = true; danglingConnection = false; //Check if there are still dangling connections foreach (ConnectionGene co in connections) { if (!hasOutgoing[co.TargetNeuronId] || !hasIncomming[co.SourceNeuronId]) { danglingConnection = true; break; } } connections.RemoveAll(delegate(ConnectionGene m) { return (!hasIncomming[m.SourceNeuronId]); }); connections.RemoveAll(delegate(ConnectionGene m) { return (!hasOutgoing[m.TargetNeuronId]); }); } if (normalizeWeights) { normalizeWeightConnections(ref connections, neurons.Count); } SharpNeatLib.NeatGenome.NeatGenome gn = new SharpNeatLib.NeatGenome.NeatGenome(0, neurons, connections, (int)(InputCount), (int)(OutputCount)); // SharpNeatLib.NeatGenome.NeatGenome sng = new SharpNeatLib.NeatGenome.NeatGenome(0, neurons, connections, (int)(totalInputCount), (int)(totalOutputCount)); gn.networkAdaptable = adaptiveNetwork; gn.networkModulatory = modulatoryNet; return gn; }
/// <summary> /// Create a default minimal genome that describes a NN with the given number of inputs and outputs. /// </summary> /// <returns></returns> public static IGenome CreateGenome(NeatParameters neatParameters, IdGenerator idGenerator, int inputNeuronCount, int outputNeuronCount, int outputsPerPolicy, float connectionProportion) { IActivationFunction actFunct; NeuronGene neuronGene; // temp variable. NeuronGeneList inputNeuronGeneList = new NeuronGeneList(); // includes bias neuron. NeuronGeneList outputNeuronGeneList = new NeuronGeneList(); NeuronGeneList neuronGeneList = new NeuronGeneList(); ConnectionGeneList connectionGeneList = new ConnectionGeneList(); // IMPORTANT NOTE: The neurons must all be created prior to any connections. That way all of the genomes // will obtain the same innovation ID's for the bias,input and output nodes in the initial population. // Create a single bias neuron. //TODO: DAVID proper activation function change to NULL? actFunct = ActivationFunctionFactory.GetActivationFunction("NullFn"); //neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Bias, actFunct); neuronGene = new NeuronGene(null, idGenerator.NextInnovationId, NeuronGene.INPUT_LAYER, NeuronType.Bias, actFunct); inputNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); // Create input neuron genes. actFunct = ActivationFunctionFactory.GetActivationFunction("NullFn"); for(int i=0; i<inputNeuronCount; i++) { //TODO: DAVID proper activation function change to NULL? //neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Input, actFunct); neuronGene = new NeuronGene(null, idGenerator.NextInnovationId, NeuronGene.INPUT_LAYER, NeuronType.Input, actFunct); inputNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); } // Create output neuron genes. //actFunct = ActivationFunctionFactory.GetActivationFunction("NullFn"); for(int i=0; i<outputNeuronCount; i++) { actFunct = ActivationFunctionFactory.GetActivationFunction("BipolarSigmoid"); //actFunct = ActivationFunctionFactory.GetRandomActivationFunction(neatParameters); //TODO: DAVID proper activation function //neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Output, actFunct); neuronGene = new NeuronGene(null, idGenerator.NextInnovationId, NeuronGene.OUTPUT_LAYER, NeuronType.Output, actFunct); outputNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); } // Loop over all possible connections from input to output nodes and create a number of connections based upon // connectionProportion. foreach(NeuronGene targetNeuronGene in outputNeuronGeneList) { foreach(NeuronGene sourceNeuronGene in inputNeuronGeneList) { // Always generate an ID even if we aren't going to use it. This is necessary to ensure connections // between the same neurons always have the same ID throughout the generated population. uint connectionInnovationId = idGenerator.NextInnovationId; if(Utilities.NextDouble() < connectionProportion) { // Ok lets create a connection. connectionGeneList.Add( new ConnectionGene(connectionInnovationId, sourceNeuronGene.InnovationId, targetNeuronGene.InnovationId, (Utilities.NextDouble() * neatParameters.connectionWeightRange ) - neatParameters.connectionWeightRange/2.0)); // Weight 0 +-5 } } } // Don't create any hidden nodes at this point. Fundamental to the NEAT way is to start minimally! // Schrum: Added outputsPerPolicy: If outputsPerPolicy == outputNeuronCount, then behaves like default NEAT return new NeatGenome(idGenerator.NextGenomeId, neuronGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount, outputsPerPolicy); }