/// <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, float connectionProportion, bool neatBrain)
        {
            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, 0f);
            inputNeuronGeneList.Add(neuronGene);
            neuronGeneList.Add(neuronGene);

            // Create input neuron genes.

            for (int i = 0; i < inputNeuronCount; i++)
            {
                //TODO: DAVID proper activation function change to NULL?
                neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Input, actFunct, 0f);
                inputNeuronGeneList.Add(neuronGene);
                neuronGeneList.Add(neuronGene);
            }

            // Create output neuron genes.
            if (neatBrain)
            {
                actFunct = ActivationFunctionFactory.GetActivationFunction("SteepenedSigmoidApproximation");
            }
            else
            {
                actFunct = ActivationFunctionFactory.GetActivationFunction("BipolarSigmoid");
            }
            for (int i = 0; i < outputNeuronCount; i++)
            {
                //actFunct = ActivationFunctionFactory.GetRandomActivationFunction(neatParameters);
                //TODO: DAVID proper activation function
                neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Output, actFunct, 1f);
                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!
            return(new NeatGenome(idGenerator.NextGenomeId, neuronGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount));
        }
Example #2
0
        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));
        }