Encog.Neural.Networks.Training.NEAT.NEATGenome.AddNeuron C# (CSharp) Method

AddNeuron() public method

Mutate the genome by adding a neuron.
public AddNeuron ( double mutationRate, int numTrysToFindOldLink ) : void
mutationRate double The mutation rate.
numTrysToFindOldLink int The number of tries to find a link to split.
return void
        public void AddNeuron(double mutationRate, int numTrysToFindOldLink)
        {

            // should we add a neuron?
            if (ThreadSafeRandom.NextDouble() > mutationRate)
            {
                return;
            }

            // the link to split
            NEATLinkGene splitLink = null;

            int sizeThreshold = inputCount + outputCount + 10;

            // if there are not at least
            int upperLimit;
            if (linksChromosome.Genes.Count < sizeThreshold)
            {
                upperLimit = NumGenes - 1 - (int)Math.Sqrt(NumGenes);
            }
            else
            {
                upperLimit = NumGenes - 1;
            }

            while ((numTrysToFindOldLink--) > 0)
            {
                // choose a link, use the square root to prefer the older links
                int i = RangeRandomizer.RandomInt(0, upperLimit);
                NEATLinkGene link = (NEATLinkGene)linksChromosome.Genes[i];

                // get the from neuron
                long fromNeuron = link.FromNeuronID;

                if ((link.Enabled)
                        && (!link.IsRecurrent)
                        && (((NEATNeuronGene)Neurons.Genes[
                                GetElementPos(fromNeuron)]).NeuronType != NEATNeuronType.Bias))
                {
                    splitLink = link;
                    break;
                }
            }

            if (splitLink == null)
            {
                return;
            }

            splitLink.Enabled = false;

            double originalWeight = splitLink.Weight;

            long from = splitLink.FromNeuronID;
            long to = splitLink.ToNeuronID;

            NEATNeuronGene fromGene = (NEATNeuronGene)Neurons.Genes[
                    GetElementPos(from)];
            NEATNeuronGene toGene = (NEATNeuronGene)Neurons.Genes[
                    GetElementPos(to)];

            double newDepth = (fromGene.SplitY + toGene.SplitY) / 2;
            double newWidth = (fromGene.SplitX + toGene.SplitX) / 2;

            // has this innovation already been tried?
            NEATInnovation innovation = ((NEATTraining)GA).Innovations.CheckInnovation(
                    from, to, NEATInnovationType.NewNeuron);

            // prevent chaining
            if (innovation != null)
            {
                long neuronID = innovation.NeuronID;

                if (AlreadyHaveThisNeuronID(neuronID))
                {
                    innovation = null;
                }
            }

            if (innovation == null)
            {
                // this innovation has not been tried, create it
                long newNeuronID = ((NEATTraining)GA).Innovations
                        .CreateNewInnovation(from, to,
                                NEATInnovationType.NewNeuron,
                                NEATNeuronType.Hidden, newWidth, newDepth);

                neuronsChromosome.Genes.Add(new NEATNeuronGene(NEATNeuronType.Hidden,
                        newNeuronID, newDepth, newWidth));

                // add the first link
                long link1ID = ((NEATTraining)GA).Population.AssignInnovationID();

                ((NEATTraining)GA).Innovations.CreateNewInnovation(from, newNeuronID,
                        NEATInnovationType.NewLink);

                NEATLinkGene link1 = new NEATLinkGene(from, newNeuronID,
                        true, link1ID, 1.0, false);

                linksChromosome.Genes.Add(link1);

                // add the second link
                long link2ID = ((NEATTraining)GA).Population.AssignInnovationID();

                ((NEATTraining)GA).Innovations.CreateNewInnovation(newNeuronID, to,
                        NEATInnovationType.NewLink);

                NEATLinkGene link2 = new NEATLinkGene(newNeuronID, to, true,
                        link2ID, originalWeight, false);

                linksChromosome.Genes.Add(link2);
            }

            else
            {
                // existing innovation
                long newNeuronID = innovation.NeuronID;

                NEATInnovation innovationLink1 = ((NEATTraining)GA).Innovations
                        .CheckInnovation(from, newNeuronID,
                                NEATInnovationType.NewLink);
                NEATInnovation innovationLink2 = ((NEATTraining)GA).Innovations
                        .CheckInnovation(newNeuronID, to,
                                NEATInnovationType.NewLink);

                if ((innovationLink1 == null) || (innovationLink2 == null))
                {
                    throw new NeuralNetworkError("NEAT Error");
                }

                NEATLinkGene link1 = new NEATLinkGene(from, newNeuronID,
                        true, innovationLink1.InnovationID, 1.0, false);
                NEATLinkGene link2 = new NEATLinkGene(newNeuronID, to, true,
                        innovationLink2.InnovationID, originalWeight, false);

                linksChromosome.Genes.Add(link1);
                linksChromosome.Genes.Add(link2);

                NEATNeuronGene newNeuron = new NEATNeuronGene(
                        NEATNeuronType.Hidden, newNeuronID, newDepth, newWidth);

                neuronsChromosome.Genes.Add(newNeuron);
            }

            return;
        }