Implements a NEAT link gene. This describes a way in which two neurons are linked. NeuroEvolution of Augmenting Topologies (NEAT) is a genetic algorithm for the generation of evolving artificial neural networks. It was developed by Ken Stanley while at The University of Texas at Austin. http://www.cs.ucf.edu/~kstanley/
Inheritance: Encog.Solve.Genetic.Genes.BasicGene
コード例 #1
0
        /// <summary>
        /// Copy from another gene.
        /// </summary>
        /// <param name="gene">The other gene.</param>
        public override void Copy(IGene gene)
        {
            NEATLinkGene other = (NEATLinkGene)gene;

            this.Enabled      = other.Enabled;
            fromNeuronID      = other.fromNeuronID;
            toNeuronID        = other.toNeuronID;
            this.InnovationId = other.InnovationId;
            recurrent         = other.recurrent;
            weight            = other.weight;
        }
コード例 #2
0
        /// <summary>
        /// Determine if this is a duplicate link.
        /// </summary>
        /// <param name="fromNeuronID">The from neuron id.</param>
        /// <param name="toNeuronID">The to neuron id.</param>
        /// <returns>True if this is a duplicate link.</returns>
        public bool IsDuplicateLink(long fromNeuronID, long toNeuronID)
        {
            foreach (IGene gene in this.Links.Genes)
            {
                NEATLinkGene linkGene = (NEATLinkGene)gene;
                if ((linkGene.FromNeuronID == fromNeuronID) &&
                    (linkGene.ToNeuronID == toNeuronID))
                {
                    return(true);
                }
            }

            return(false);
        }
コード例 #3
0
        /// <summary>
        /// Convert the genes to an actual network.
        /// </summary>
        public override void Decode()
        {
            NEATPattern pattern = new NEATPattern();

            IList <NEATNeuron> neurons = pattern.Neurons;


            foreach (IGene gene in Neurons.Genes)
            {
                NEATNeuronGene neuronGene = (NEATNeuronGene)gene;
                NEATNeuron     neuron     = new NEATNeuron(
                    neuronGene.NeuronType, neuronGene.Id, neuronGene
                    .SplitY, neuronGene.SplitX, neuronGene
                    .ActivationResponse);

                neurons.Add(neuron);
            }

            // now to create the links.
            foreach (IGene gene in Links.Genes)
            {
                NEATLinkGene linkGene = (NEATLinkGene)gene;
                if (linkGene.Enabled)
                {
                    int        element    = GetElementPos(linkGene.FromNeuronID);
                    NEATNeuron fromNeuron = neurons[element];

                    element = GetElementPos(linkGene.ToNeuronID);
                    NEATNeuron toNeuron = neurons[element];

                    NEATLink link = new NEATLink(linkGene.Weight,
                                                 fromNeuron, toNeuron, linkGene.IsRecurrent);

                    fromNeuron.OutputboundLinks.Add(link);
                    toNeuron.InboundLinks.Add(link);
                }
            }

            pattern.NEATActivation     = (((NEATTraining)GA).NeatActivationFunction);
            pattern.ActivationFunction = (((NEATTraining)GA).OutputActivationFunction);
            pattern.InputNeurons       = (inputCount);
            pattern.OutputNeurons      = (outputCount);
            pattern.Snapshot           = ((NEATTraining)GA).Snapshot;

            Organism = pattern.Generate();
        }
コード例 #4
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;
             }
         }
     }
 }
コード例 #5
0
        /// <summary>
        /// Construct a genome by copying another.
        /// </summary>
        /// <param name="other">The other genome.</param>
        public NEATGenome(NEATGenome other)
            : base(other.GA)
        {
            neuronsChromosome = new Chromosome();
            linksChromosome   = new Chromosome();

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

            GenomeID      = other.GenomeID;
            networkDepth  = other.networkDepth;
            Score         = other.Score;
            AdjustedScore = other.AdjustedScore;
            AmountToSpawn = other.AmountToSpawn;
            inputCount    = other.inputCount;
            outputCount   = other.outputCount;
            speciesID     = other.speciesID;

            // copy neurons
            foreach (IGene gene in other.Neurons.Genes)
            {
                NEATNeuronGene oldGene = (NEATNeuronGene)gene;
                NEATNeuronGene newGene = new NEATNeuronGene(oldGene.NeuronType
                                                            , oldGene.Id, oldGene.SplitX,
                                                            oldGene.SplitY, oldGene.Recurrent, oldGene
                                                            .ActivationResponse);
                this.neuronsChromosome.Genes.Add(newGene);
            }

            // copy links
            foreach (IGene gene in other.Links.Genes)
            {
                NEATLinkGene oldGene = (NEATLinkGene)gene;
                NEATLinkGene newGene = new NEATLinkGene(oldGene
                                                        .FromNeuronID, oldGene.ToNeuronID, oldGene
                                                        .Enabled, oldGene.InnovationId, oldGene
                                                        .Weight, oldGene.IsRecurrent);
                Links.Genes.Add(newGene);
            }
        }
コード例 #6
0
        /// <summary>
        /// Construct an innovation list.
        /// </summary>
        /// <param name="population">The population.</param>
        /// <param name="links">The links.</param>
        /// <param name="neurons">The neurons.</param>
        public NEATInnovationList(IPopulation population, Chromosome links, Chromosome neurons)
        {
            this.population = population;
            foreach (IGene gene in neurons.Genes)
            {
                NEATNeuronGene neuronGene = (NEATNeuronGene)gene;

                NEATInnovation innovation = new NEATInnovation(neuronGene,
                                                               population.AssignInnovationID(), AssignNeuronID());

                Innovations.Add(innovation);
            }

            foreach (IGene gene in links.Genes)
            {
                NEATLinkGene   linkGene   = (NEATLinkGene)gene;
                NEATInnovation innovation = new NEATInnovation(linkGene
                                                               .FromNeuronID, linkGene.ToNeuronID,
                                                               NEATInnovationType.NewLink, this.population.AssignInnovationID());
                Innovations.Add(innovation);
            }
        }
コード例 #7
0
        /// <summary>
        /// Mutate the genome by adding a neuron. 
        /// </summary>
        /// <param name="mutationRate">The mutation rate.</param>
        /// <param name="numTrysToFindOldLink">The number of tries to find a link to split.</param>
        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;
        }
コード例 #8
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);
            }
        }
コード例 #9
0
        /// <summary>
        /// Construct a genome by copying another. 
        /// </summary>
        /// <param name="other">The other genome.</param>
        public NEATGenome(NEATGenome other)
            : base(other.GA)
        {

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

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

            GenomeID = other.GenomeID;
            networkDepth = other.networkDepth;
            Score = other.Score;
            AdjustedScore = other.AdjustedScore;
            AmountToSpawn = other.AmountToSpawn;
            inputCount = other.inputCount;
            outputCount = other.outputCount;
            speciesID = other.speciesID;

            // copy neurons
            foreach (IGene gene in other.Neurons.Genes)
            {
                NEATNeuronGene oldGene = (NEATNeuronGene)gene;
                NEATNeuronGene newGene = new NEATNeuronGene(oldGene.NeuronType
                   , oldGene.Id, oldGene.SplitX,
                       oldGene.SplitY, oldGene.Recurrent, oldGene
                               .ActivationResponse);
                this.neuronsChromosome.Genes.Add(newGene);
            }

            // copy links
            foreach (IGene gene in other.Links.Genes)
            {
                NEATLinkGene oldGene = (NEATLinkGene)gene;
                NEATLinkGene newGene = new NEATLinkGene(oldGene
                        .FromNeuronID, oldGene.ToNeuronID, oldGene
                        .Enabled, oldGene.InnovationId, oldGene
                        .Weight, oldGene.IsRecurrent);
                Links.Genes.Add(newGene);
            }

        }
コード例 #10
0
        /// <summary>
        /// Mutate the genome by adding a neuron.
        /// </summary>
        /// <param name="mutationRate">The mutation rate.</param>
        /// <param name="numTrysToFindOldLink">The number of tries to find a link to split.</param>
        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;
        }
コード例 #11
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);
            }
        }
コード例 #12
0
        /// <summary>
        /// Perform the crossover.
        /// </summary>
        /// <param name="mom">The mother.</param>
        /// <param name="dad">The father.</param>
        /// <returns>The child.</returns>
        public NEATGenome PerformCrossover(NEATGenome mom, NEATGenome dad)
        {
            NEATParent best;

            // first determine who is more fit, the mother or the father?
            if (mom.Score == dad.Score)
            {
                if (mom.NumGenes == dad.NumGenes)
                {
                    if (ThreadSafeRandom.NextDouble() > 0)
                    {
                        best = NEATParent.Mom;
                    }
                    else
                    {
                        best = NEATParent.Dad;
                    }
                }

                else
                {
                    if (mom.NumGenes < dad.NumGenes)
                    {
                        best = NEATParent.Mom;
                    }

                    else
                    {
                        best = NEATParent.Dad;
                    }
                }
            }

            else
            {
                if (Comparator.IsBetterThan(mom.Score, dad.Score))
                {
                    best = NEATParent.Mom;
                }

                else
                {
                    best = NEATParent.Dad;
                }
            }

            Chromosome babyNeurons = new Chromosome();
            Chromosome babyGenes   = new Chromosome();

            List <long> vecNeurons = new List <long>();

            int curMom = 0;
            int curDad = 0;

            NEATLinkGene momGene;
            NEATLinkGene dadGene;

            NEATLinkGene selectedGene = null;

            while ((curMom < mom.NumGenes) || (curDad < dad.NumGenes))
            {
                if (curMom < mom.NumGenes)
                {
                    momGene = (NEATLinkGene)mom.Links.Genes[curMom];
                }
                else
                {
                    momGene = null;
                }

                if (curDad < dad.NumGenes)
                {
                    dadGene = (NEATLinkGene)dad.Links.Genes[curDad];
                }
                else
                {
                    dadGene = null;
                }

                if ((momGene == null) && (dadGene != null))
                {
                    if (best == NEATParent.Dad)
                    {
                        selectedGene = dadGene;
                    }
                    curDad++;
                }
                else if ((dadGene == null) && (momGene != null))
                {
                    if (best == NEATParent.Mom)
                    {
                        selectedGene = momGene;
                    }
                    curMom++;
                }
                else if (momGene.InnovationId < dadGene.InnovationId)
                {
                    if (best == NEATParent.Mom)
                    {
                        selectedGene = momGene;
                    }
                    curMom++;
                }
                else if (dadGene.InnovationId < momGene.InnovationId)
                {
                    if (best == NEATParent.Dad)
                    {
                        selectedGene = dadGene;
                    }
                    curDad++;
                }
                else if (dadGene.InnovationId == momGene.InnovationId)
                {
                    if (ThreadSafeRandom.NextDouble() < 0.5f)
                    {
                        selectedGene = momGene;
                    }

                    else
                    {
                        selectedGene = dadGene;
                    }
                    curMom++;
                    curDad++;
                }

                if (babyGenes.Genes.Count == 0)
                {
                    babyGenes.Genes.Add(selectedGene);
                }

                else
                {
                    if (babyGenes.Genes[babyGenes.Genes.Count - 1]
                        .InnovationId != selectedGene.InnovationId)
                    {
                        babyGenes.Genes.Add(selectedGene);
                    }
                }

                // Check if we already have the nodes referred to in SelectedGene.
                // If not, they need to be added.
                AddNeuronID(selectedGene.FromNeuronID, vecNeurons);
                AddNeuronID(selectedGene.ToNeuronID, vecNeurons);
            }

            // now create the required nodes. First sort them into order
            vecNeurons.Sort();

            for (int i = 0; i < vecNeurons.Count; i++)
            {
                babyNeurons.Genes.Add(this.Innovations.CreateNeuronFromID(
                                          vecNeurons[i]));
            }

            // finally, create the genome
            NEATGenome babyGenome = new NEATGenome(this, Population
                                                   .AssignGenomeID(), babyNeurons, babyGenes, mom.InputCount,
                                                   mom.OutputCount);

            return(babyGenome);
        }