/// <summary>
        /// Run the network until thermal equalibrium is established.
        /// </summary>
        public void EstablishEquilibrium()
        {
            int n, i;

            int count = this.ThermalSynapse.FromNeuronCount;

            for (i = 0; i < count; i++)
            {
                on[i]  = 0;
                off[i] = 0;
            }

            for (n = 0; n < runCycles * count; n++)
            {
                Run(i = (int)RangeRandomizer.Randomize(0, count - 1));
            }
            for (n = 0; n < this.annealCycles * count; n++)
            {
                Run(i = (int)RangeRandomizer.Randomize(0, count - 1));
                if (this.CurrentState.GetBoolean(i))
                {
                    on[i]++;
                }
                else
                {
                    off[i]++;
                }
            }

            for (i = 0; i < count; i++)
            {
                this.CurrentState.SetBoolean(i, on[i] > off[i]);
            }
        }
示例#2
0
        /// <summary>
        /// Enable(or disable) a connection.
        /// </summary>
        /// <param name="synapse">The synapse.</param>
        /// <param name="fromNeuron">The from neuron.</param>
        /// <param name="toNeuron">The to neuron.</param>
        /// <param name="enable">True, if enabled.</param>
        public void EnableConnection(ISynapse synapse, int fromNeuron, int toNeuron, bool enable)
        {
            if (synapse.WeightMatrix == null)
            {
                throw new NeuralNetworkError("Can't enable/disable connection on a synapse that does not have a weight matrix.");
            }

            double value = synapse.WeightMatrix[fromNeuron, toNeuron];

            if (enable)
            {
                if (!this.structure.IsConnectionLimited)
                {
                    return;
                }

                if (Math.Abs(value) < this.structure.ConnectionLimit)
                {
                    synapse.WeightMatrix[fromNeuron, toNeuron] = RangeRandomizer.Randomize(-1, 1);
                }
            }
            else
            {
                if (!this.structure.IsConnectionLimited)
                {
                    this.Properties[BasicNetwork.TAG_LIMIT] = BasicNetwork.DEFAULT_CONNECTION_LIMIT;
                    this.structure.FinalizeStructure();
                }
                synapse.WeightMatrix[fromNeuron, toNeuron] = 0;
            }
        }
示例#3
0
        /// <summary>
        /// Enable, or disable, a connection.
        /// </summary>
        ///
        /// <param name="fromLayer">The layer that contains the from neuron.</param>
        /// <param name="fromNeuron">The source neuron.</param>
        /// <param name="toNeuron">The target connection.</param>
        /// <param name="enable">True to enable, false to disable.</param>
        public void EnableConnection(int fromLayer,
                                     int fromNeuron, int toNeuron, bool enable)
        {
            double v = GetWeight(fromLayer, fromNeuron, toNeuron);

            if (enable)
            {
                if (!_structure.ConnectionLimited)
                {
                    return;
                }

                if (Math.Abs(v) < _structure.ConnectionLimit)
                {
                    SetWeight(fromLayer, fromNeuron, toNeuron,
                              RangeRandomizer.Randomize(-1, 1));
                }
            }
            else
            {
                if (!_structure.ConnectionLimited)
                {
                    SetProperty(TagLimit,
                                DefaultConnectionLimit);
                    _structure.UpdateProperties();
                }
                SetWeight(fromLayer, fromNeuron, toNeuron, 0);
            }
        }
示例#4
0
 /// <summary>
 /// Randomize the matrix.
 /// </summary>
 ///
 /// <param name="min">Minimum random value.</param>
 /// <param name="max">Maximum random value.</param>
 public void Randomize(double min, double max)
 {
     for (int row = 0; row < Rows; row++)
     {
         for (int col = 0; col < Cols; col++)
         {
             matrix[row][col] = RangeRandomizer.Randomize(min, max);
         }
     }
 }
示例#5
0
        /// <summary>
        /// Create a new genome with the specified connection density. This
        /// constructor is typically used to create the initial population.
        /// </summary>
        /// <param name="rnd">Random number generator.</param>
        /// <param name="pop">The population.</param>
        /// <param name="inputCount">The input count.</param>
        /// <param name="outputCount">The output count.</param>
        /// <param name="connectionDensity">The connection density.</param>
        public NEATGenome(EncogRandom rnd, NEATPopulation pop,
                          int inputCount, int outputCount,
                          double connectionDensity)
        {
            AdjustedScore = 0;
            InputCount    = inputCount;
            OutputCount   = outputCount;

            // get the activation function
            IActivationFunction af = pop.ActivationFunctions.PickFirst();

            // first bias
            int innovationId = 0;
            var biasGene     = new NEATNeuronGene(NEATNeuronType.Bias, af,
                                                  inputCount, innovationId++);

            _neuronsList.Add(biasGene);

            // then inputs

            for (var i = 0; i < inputCount; i++)
            {
                var gene = new NEATNeuronGene(NEATNeuronType.Input, af,
                                              i, innovationId++);
                _neuronsList.Add(gene);
            }

            // then outputs

            for (int i = 0; i < outputCount; i++)
            {
                var gene = new NEATNeuronGene(NEATNeuronType.Output, af,
                                              i + inputCount + 1, innovationId++);
                _neuronsList.Add(gene);
            }

            // and now links
            for (var i = 0; i < inputCount + 1; i++)
            {
                for (var j = 0; j < outputCount; j++)
                {
                    // make sure we have at least one connection
                    if (_linksList.Count < 1 ||
                        rnd.NextDouble() < connectionDensity)
                    {
                        long   fromId = this._neuronsList[i].Id;
                        long   toId   = this._neuronsList[inputCount + j + 1].Id;
                        double w      = RangeRandomizer.Randomize(rnd, -pop.WeightRange, pop.WeightRange);
                        var    gene   = new NEATLinkGene(fromId, toId, true,
                                                         innovationId++, w);
                        _linksList.Add(gene);
                    }
                }
            }
        }
示例#6
0
        /// <inheritdoc/>
        public override void PerformOperation(EncogRandom rnd, IGenome[] parents, int parentIndex,
                                              IGenome[] offspring, int offspringIndex)
        {
            int countTrysToAddLink = Owner.MaxTries;

            NEATGenome target = ObtainGenome(parents, parentIndex, offspring,
                                             offspringIndex);

            // the link will be between these two neurons
            long neuron1Id = -1;
            long neuron2Id = -1;

            // try to add a link
            while ((countTrysToAddLink--) > 0)
            {
                NEATNeuronGene neuron1 = ChooseRandomNeuron(target, true);
                NEATNeuronGene neuron2 = ChooseRandomNeuron(target, false);

                if (neuron1 == null || neuron2 == null)
                {
                    return;
                }

                // do not duplicate
                // do not go to a bias neuron
                // do not go from an output neuron
                // do not go to an input neuron
                if (!IsDuplicateLink(target, neuron1.Id, neuron2.Id) &&
                    (neuron2.NeuronType != NEATNeuronType.Bias) &&
                    (neuron2.NeuronType != NEATNeuronType.Input))
                {
                    if (((NEATPopulation)Owner.Population).ActivationCycles != 1 ||
                        neuron1.NeuronType != NEATNeuronType.Output)
                    {
                        neuron1Id = neuron1.Id;
                        neuron2Id = neuron2.Id;
                        break;
                    }
                }
            }

            // did we fail to find a link
            if ((neuron1Id < 0) || (neuron2Id < 0))
            {
                return;
            }

            double r = ((NEATPopulation)target.Population).WeightRange;

            CreateLink(target, neuron1Id, neuron2Id,
                       RangeRandomizer.Randomize(rnd, -r, r));
            target.SortGenes();
        }
示例#7
0
        /// <summary>
        ///     Makes random inputs by randomizing with encog randomize , the normal random from net framework library.
        ///     a quick and easy way to test data and and train networks.
        /// </summary>
        /// <param name="number">The number.</param>
        /// <returns></returns>
        public static double[] MakeRandomInputs(int number)
        {
            var rdn      = new Random();
            var encogRnd = new RangeRandomizer(-1, 1);
            var x        = new double[number];

            for (int i = 0; i < number; i++)
            {
                x[i] = encogRnd.Randomize((rdn.NextDouble()));
            }
            return(x);
        }
示例#8
0
 /// <summary>
 /// Mutate the activation response.
 /// </summary>
 ///
 /// <param name="mutateRate">The mutation rate.</param>
 /// <param name="maxPertubation">The maximum to perturb it by.</param>
 public void MutateActivationResponse(double mutateRate,
                                      double maxPertubation)
 {
     foreach (IGene gene  in  neuronsChromosome.Genes)
     {
         if (ThreadSafeRandom.NextDouble() < mutateRate)
         {
             var neuronGene = (NEATNeuronGene)gene;
             neuronGene.ActivationResponse = neuronGene.ActivationResponse
                                             + RangeRandomizer.Randomize(-1, 1) * maxPertubation;
         }
     }
 }
示例#9
0
        /// <summary>
        /// Set the gausian components to random values.
        /// </summary>
        /// <param name="dimensions">The number of dimensions in the network.</param>
        /// <param name="min">The minimum value for the centers, widths and peaks.</param>
        /// <param name="max">The maximum value for the centers, widths and peaks.</param>
        /// <param name="t">The RBF to use.</param>
        public void RandomizeRBFCentersAndWidths(int dimensions, double min, double max, RBFEnum t)
        {
            double[] centers = new double[dimensions];

            for (int i = 0; i < dimensions; i++)
            {
                centers[i] = RangeRandomizer.Randomize(min, max);
            }

            for (int i = 0; i < this.NeuronCount; i++)
            {
                SetRBFFunction(i, t, centers, RangeRandomizer.Randomize(min, max));
            }
        }
示例#10
0
        /// <summary>
        /// Construct a genome, do not provide links and neurons.
        /// </summary>
        /// <param name="training">The owner object.</param>
        /// <param name="id">The genome id.</param>
        /// <param name="inputCount">The input count.</param>
        /// <param name="outputCount">The output count.</param>
        public NEATGenome(NEATTraining training, long id,
                          int inputCount, int outputCount)
            : base(training)
        {
            GenomeID         = id;
            AdjustedScore    = 0;
            this.inputCount  = inputCount;
            this.outputCount = outputCount;
            AmountToSpawn    = 0;
            speciesID        = 0;

            double inputRowSlice = 0.8 / (inputCount);

            neuronsChromosome = new Chromosome();
            linksChromosome   = new Chromosome();

            for (int i = 0; i < inputCount; i++)
            {
                neuronsChromosome.Genes.Add(new NEATNeuronGene(NEATNeuronType.Input, i,
                                                               0, 0.1 + i * inputRowSlice));
            }

            neuronsChromosome.Genes.Add(new NEATNeuronGene(NEATNeuronType.Bias,
                                                           inputCount, 0, 0.9));

            double outputRowSlice = 1 / (double)(outputCount + 1);

            for (int i = 0; i < outputCount; i++)
            {
                neuronsChromosome.Genes.Add(new NEATNeuronGene(NEATNeuronType.Output, i
                                                               + inputCount + 1, 1, (i + 1) * outputRowSlice));
            }

            for (int i = 0; i < inputCount + 1; i++)
            {
                for (int j = 0; j < outputCount; j++)
                {
                    linksChromosome.Genes.Add(new NEATLinkGene(
                                                  ((NEATNeuronGene)neuronsChromosome.Genes[i]).Id,
                                                  ((NEATNeuronGene)Neurons.Genes[inputCount + j + 1])
                                                  .Id, true, inputCount + outputCount + 1
                                                  + NumGenes, RangeRandomizer.Randomize(-1,
                                                                                        1), false));
                }
            }

            this.Chromosomes.Add(neuronsChromosome);
            this.Chromosomes.Add(linksChromosome);
        }
示例#11
0
        /// <summary>
        /// Construct a genome, do not provide links and neurons.
        /// </summary>
        ///
        /// <param name="id">The genome id.</param>
        /// <param name="inputCount_0">The input count.</param>
        /// <param name="outputCount_1">The output count.</param>
        public NEATGenome(long id, int inputCount_0, int outputCount_1)
        {
            GenomeID      = id;
            AdjustedScore = 0;
            inputCount    = inputCount_0;
            outputCount   = outputCount_1;
            AmountToSpawn = 0;
            speciesID     = 0;

            double inputRowSlice = 0.8d / (inputCount_0);

            neuronsChromosome = new Chromosome();
            linksChromosome   = new Chromosome();

            Chromosomes.Add(neuronsChromosome);
            Chromosomes.Add(linksChromosome);

            for (int i = 0; i < inputCount_0; i++)
            {
                neuronsChromosome.Add(new NEATNeuronGene(NEATNeuronType.Input,
                                                         i, 0, 0.1d + i * inputRowSlice));
            }

            neuronsChromosome.Add(new NEATNeuronGene(NEATNeuronType.Bias,
                                                     inputCount_0, 0, 0.9d));

            double outputRowSlice = 1 / (double)(outputCount_1 + 1);

            for (int i_2 = 0; i_2 < outputCount_1; i_2++)
            {
                neuronsChromosome.Add(new NEATNeuronGene(
                                          NEATNeuronType.Output, i_2 + inputCount_0 + 1, 1, (i_2 + 1)
                                          * outputRowSlice));
            }

            for (int i_3 = 0; i_3 < inputCount_0 + 1; i_3++)
            {
                for (int j = 0; j < outputCount_1; j++)
                {
                    linksChromosome.Add(new NEATLinkGene(
                                            ((NEATNeuronGene)neuronsChromosome.Get(i_3)).Id,
                                            ((NEATNeuronGene)Neurons.Get(
                                                 inputCount_0 + j + 1)).Id, true, inputCount_0
                                            + outputCount_1 + 1 + NumGenes,
                                            RangeRandomizer.Randomize(-1, 1), false));
                }
            }
        }
示例#12
0
        /// <summary>
        /// Set the RBF components to random values.
        /// </summary>
        ///
        /// <param name="min">Minimum random value.</param>
        /// <param name="max">Max random value.</param>
        /// <param name="t">The type of RBF to use.</param>
        public void RandomizeRBFCentersAndWidths(double min,
                                                 double max, RBFEnum t)
        {
            int dimensions = InputCount;
            var centers    = new double[dimensions];

            for (int i = 0; i < dimensions; i++)
            {
                centers[i] = RangeRandomizer.Randomize(min, max);
            }

            for (int i = 0; i < _flat.RBF.Length; i++)
            {
                SetRBFFunction(i, t, centers, RangeRandomizer.Randomize(min, max));
            }
        }
示例#13
0
        /// <summary>
        /// Run the network for the specified neuron.
        /// </summary>
        ///
        /// <param name="i">The neuron to run for.</param>
        public void Run(int i)
        {
            int j;

            int count = NeuronCount;

            double sum = 0;

            for (j = 0; j < count; j++)
            {
                sum += GetWeight(i, j) * ((CurrentState.GetBoolean(j)) ? 1 : 0);
            }
            sum -= _threshold[i];
            double probability = 1 / (1 + BoundMath.Exp(-sum / _temperature));

            CurrentState.SetBoolean(i, RangeRandomizer.Randomize(0, 1) <= probability);
        }
示例#14
0
        public static IMLDataSet CreateNoisyXORDataSet(int count)
        {
            var result = new BasicMLDataSet();

            for (int i = 0; i < count; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    var inputData = new BasicMLData(XORInput[j]);
                    var idealData = new BasicMLData(XORIdeal[j]);
                    var pair      = new BasicMLDataPair(inputData, idealData);
                    inputData[0] = inputData[0] + RangeRandomizer.Randomize(-0.1, 0.1);
                    inputData[1] = inputData[1] + RangeRandomizer.Randomize(-0.1, 0.1);
                    result.Add(pair);
                }
            }
            return(result);
        }
        /// <summary>
        /// Select a gene using a tournament.
        /// </summary>
        /// <param name="numComparisons">The number of compares to do.</param>
        /// <returns>The chosen genome.</returns>
        public NEATGenome TournamentSelection(int numComparisons)
        {
            double bestScoreSoFar = 0;

            int chosenOne = 0;

            for (int i = 0; i < numComparisons; ++i)
            {
                var thisTry = (int)RangeRandomizer.Randomize(0, Population.Size() - 1);

                if (Population.Get(thisTry).Score > bestScoreSoFar)
                {
                    chosenOne = thisTry;

                    bestScoreSoFar = Population.Get(thisTry).Score;
                }
            }

            return((NEATGenome)Population.Get(chosenOne));
        }
示例#16
0
 /// <summary>
 /// Mutate the weights.
 /// </summary>
 /// <param name="mutateRate">The mutation rate.</param>
 /// <param name="probNewMutate">The probability of a whole new weight.</param>
 /// <param name="maxPertubation">The max perturbation.</param>
 public void MutateWeights(double mutateRate, double probNewMutate,
                           double maxPertubation)
 {
     foreach (IGene gene in linksChromosome.Genes)
     {
         NEATLinkGene linkGene = (NEATLinkGene)gene;
         if (ThreadSafeRandom.NextDouble() < mutateRate)
         {
             if (ThreadSafeRandom.NextDouble() < probNewMutate)
             {
                 linkGene.Weight = RangeRandomizer.Randomize(-1, 1);
             }
             else
             {
                 linkGene.Weight += RangeRandomizer.Randomize(-1, 1)
                                    * maxPertubation;
             }
         }
     }
 }
示例#17
0
        /// <summary>
        /// Select a gene using a tournament.
        /// </summary>
        /// <param name="numComparisons">The number of compares to do.</param>
        /// <returns>The chosen genome.</returns>
        public NEATGenome TournamentSelection(int numComparisons)
        {
            double bestScoreSoFar = 0;

            int ChosenOne = 0;

            for (int i = 0; i < numComparisons; ++i)
            {
                int ThisTry = (int)RangeRandomizer.Randomize(0,
                                                             Population.Genomes.Count - 1);

                if (Population.Genomes[ThisTry].Score > bestScoreSoFar)
                {
                    ChosenOne = ThisTry;

                    bestScoreSoFar = Population.Genomes[ThisTry].Score;
                }
            }

            return((NEATGenome)Population.Genomes[ChosenOne]);
        }
        /// <summary>
        /// Choose a parent to mate. Choose from the population, determined by the
        /// survival rate. From this pool, a random parent is chosen.
        /// </summary>
        ///
        /// <returns>The parent.</returns>
        public IGenome ChooseParent()
        {
            IGenome baby;

            // If there is a single member, then choose that one.
            if (_members.Count == 1)
            {
                baby = _members[0];
            }
            else
            {
                // If there are many, then choose the population based on survival
                // rate
                // and select a random genome.
                int maxIndexSize = (int)(_population.SurvivalRate * _members.Count) + 1;
                var theOne       = (int)RangeRandomizer.Randomize(0, maxIndexSize);
                baby = _members[theOne];
            }

            return(baby);
        }
示例#19
0
        /// <summary>
        /// Run the network until thermal equilibrium is established.
        /// </summary>
        ///
        public void EstablishEquilibrium()
        {
            int count = NeuronCount;

            if (_on == null)
            {
                _on  = new int[count];
                _off = new int[count];
            }

            for (int i = 0; i < count; i++)
            {
                _on[i]  = 0;
                _off[i] = 0;
            }

            for (int n = 0; n < _runCycles * count; n++)
            {
                Run((int)RangeRandomizer.Randomize(0, count - 1));
            }
            for (int n = 0; n < _annealCycles * count; n++)
            {
                var i = (int)RangeRandomizer.Randomize(0, count - 1);
                Run(i);
                if (CurrentState.GetBoolean(i))
                {
                    _on[i]++;
                }
                else
                {
                    _off[i]++;
                }
            }

            for (int i = 0; i < count; i++)
            {
                CurrentState.SetBoolean(i, _on[i] > _off[i]);
            }
        }
示例#20
0
        public SOMColors()
        {
            InitializeComponent();

            this.network  = CreateNetwork();
            this.gaussian = new NeighborhoodRBF(RBFEnum.Gaussian, SOMColors.WIDTH, SOMColors.HEIGHT);
            this.train    = new BasicTrainSOM(this.network, 0.01, null, gaussian);

            train.ForceWinner = false;

            samples = new List <IMLData>();
            for (int i = 0; i < 15; i++)
            {
                IMLData data = new BasicMLData(3);
                data.Data[0] = RangeRandomizer.Randomize(-1, 1);
                data.Data[1] = RangeRandomizer.Randomize(-1, 1);
                data.Data[2] = RangeRandomizer.Randomize(-1, 1);
                samples.Add(data);
            }

            this.train.SetAutoDecay(100, 0.8, 0.003, 30, 5);
        }
示例#21
0
        private void Do()
        {
            network  = CreateNetwork();
            gaussian = new NeighborhoodRBF(RBFEnum.Gaussian, WIDTH, HEIGHT);
            train    = new BasicTrainSOM(network, 0.01, null, gaussian);

            train.ForceWinner = false;

            samples = new List <IMLData>();
            for (int i = 0; i < 200; i++)
            {
                var data = new BasicMLData(3);
                data.Data[0] = RangeRandomizer.Randomize(-1, 1);
                data.Data[1] = RangeRandomizer.Randomize(-1, 1);
                data.Data[2] = RangeRandomizer.Randomize(-1, 1);
                samples.Add(data);
            }

            train.SetAutoDecay(100, 0.8, 0.003, 30, 5);

            iteration           = 0;
            updateTimer.Enabled = true;
        }
示例#22
0
        /// <summary>
        /// Run the network for the specified neuron.
        /// </summary>
        /// <param name="i">The neuron to run for.</param>
        void Run(int i)
        {
            int    j;
            double sum, probability;

            int count = this.ThermalSynapse.FromNeuronCount;

            sum = 0;
            for (j = 0; j < count; j++)
            {
                sum += this.ThermalSynapse.WeightMatrix[i, j]
                       * (this.CurrentState.GetBoolean(j) ? 1 : 0);
            }
            sum        -= this.ThermalLayer.BiasWeights[i];
            probability = 1 / (1 + BoundMath.Exp(-sum / temperature));
            if (RangeRandomizer.Randomize(0, 1) <= probability)
            {
                this.CurrentState.SetBoolean(i, true);
            }
            else
            {
                this.CurrentState.SetBoolean(i, false);
            }
        }
示例#23
0
        /// <summary>
        /// Mutate the genome by adding a link to this genome.
        /// </summary>
        /// <param name="mutationRate">The mutation rate.</param>
        /// <param name="chanceOfLooped">The chance of a self-connected neuron.</param>
        /// <param name="numTrysToFindLoop">The number of tries to find a loop.</param>
        /// <param name="numTrysToAddLink">The number of tries to add a link.</param>
        public void AddLink(double mutationRate, double chanceOfLooped,
                            int numTrysToFindLoop, int numTrysToAddLink)
        {
            // should we even add the link
            if (ThreadSafeRandom.NextDouble() > mutationRate)
            {
                return;
            }

            // the link will be between these two neurons
            long neuron1ID = -1;
            long neuron2ID = -1;

            bool recurrent = false;

            // a self-connected loop?
            if (ThreadSafeRandom.NextDouble() < chanceOfLooped)
            {
                // try to find(randomly) a neuron to add a self-connected link to
                while ((numTrysToFindLoop--) > 0)
                {
                    NEATNeuronGene neuronGene = ChooseRandomNeuron(false);

                    // no self-links on input or bias neurons
                    if (!neuronGene.Recurrent &&
                        (neuronGene.NeuronType != NEATNeuronType.Bias) &&
                        (neuronGene.NeuronType != NEATNeuronType.Input))
                    {
                        neuron1ID = neuron2ID = neuronGene.Id;

                        neuronGene.Recurrent = true;
                        recurrent            = true;

                        numTrysToFindLoop = 0;
                    }
                }
            }
            else
            {
                // try to add a regular link
                while ((numTrysToAddLink--) > 0)
                {
                    NEATNeuronGene neuron1 = ChooseRandomNeuron(true);
                    NEATNeuronGene neuron2 = ChooseRandomNeuron(false);

                    if (!IsDuplicateLink(neuron1ID, neuron2ID) &&
                        (neuron1.Id != neuron2.Id) &&
                        (neuron2.NeuronType != NEATNeuronType.Bias))
                    {
                        neuron1ID = -1;
                        neuron2ID = -1;
                        break;
                    }
                }
            }

            // did we fail to find a link
            if ((neuron1ID < 0) || (neuron2ID < 0))
            {
                return;
            }

            // check to see if this innovation has already been tried
            NEATInnovation innovation = ((NEATTraining)GA).Innovations
                                        .CheckInnovation(neuron1ID, neuron1ID,
                                                         NEATInnovationType.NewLink);

            // see if this is a recurrent(backwards) link
            NEATNeuronGene neuronGene2 = (NEATNeuronGene)neuronsChromosome.Genes
                                         [GetElementPos(neuron1ID)];

            if (neuronGene2.SplitY > neuronGene2.SplitY)
            {
                recurrent = true;
            }

            // is this a new innovation?
            if (innovation == null)
            {
                // new innovation
                ((NEATTraining)GA).Innovations.CreateNewInnovation(neuron1ID, neuron2ID,
                                                                   NEATInnovationType.NewLink);

                long id2 = ((NEATTraining)GA).Population.AssignInnovationID();

                NEATLinkGene linkGene = new NEATLinkGene(neuron1ID,
                                                         neuron2ID, true, id2, RangeRandomizer.Randomize(-1, 1),
                                                         recurrent);
                linksChromosome.Genes.Add(linkGene);
            }
            else
            {
                // existing innovation
                NEATLinkGene linkGene = new NEATLinkGene(neuron1ID,
                                                         neuron2ID, true, innovation.InnovationID,
                                                         RangeRandomizer.Randomize(-1, 1), recurrent);
                linksChromosome.Genes.Add(linkGene);
            }
        }
 /// <inheritdoc/>
 public void MutateWeight(EncogRandom rnd, NEATLinkGene linkGene, double weightRange)
 {
     linkGene.Weight = RangeRandomizer.Randomize(rnd, -weightRange,
                                                 weightRange);
 }