Exemplo n.º 1
0
 /// <summary>
 /// Add an innovation.
 /// </summary>
 ///
 /// <param name="innovation">The innovation to add.</param>
 public void Add(IInnovation innovation)
 {
     _list.Add(innovation);
 }
Exemplo n.º 2
0
 public void Add(IInnovation innovation)
 {
     this._list.Add(innovation);
 }
Exemplo n.º 3
0
        /// <summary>
        /// Crosses two parents to derive a new genome for a new child <see cref="INeatNetwork"/>
        /// </summary>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <param name="fitnessState"></param>
        /// <returns></returns>
        public IInnovation[] DeriveGenome(INeatNetwork left, INeatNetwork right, FitnessState fitnessState)
        {
            // align the genomes so we can select and create a new genome
            var GenomeMatches = AlignGenomes(left, right);

            // per https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.28.5457&rep=rep1&type=pdf pg 12
            //  Matching genes are inherited randomly, whereas disjoint genes(those that do not match in the middle) and excess genes (those that do not match in the end) are inherited from the more fit parent. Whith equal fitnesses, disjoint and excess genes are also inherited randomly.

            // if the right length is larger that means any excess in the genome belongs to the right
            int additionalGenomeSize = 0;

            bool inheritWholeExcess = false;

            // check to see who is responsible for the excess genes
            bool rightExcess = right.Innovations.Length > left.Innovations.Length;

            bool inheritRandomExcess = false;

            int amountOfDisjointGenesToInherit = 0;
            int amountOfExcessGenesToInherit   = 0;

            // determine if there is any excess or disjoint genes to inherit
            if (GenomeMatches.Excess.Length != 0 || GenomeMatches.LeftDisjoint.Length != 0 || GenomeMatches.RightDisjoint.Length != 0)
            {
                switch (fitnessState)
                {
                // if the right is more fit and the excess belongs to the right inherit the excess and the right disjoints
                case FitnessState.RightMoreFit:

                    inheritWholeExcess = rightExcess;

                    if (inheritWholeExcess)
                    {
                        additionalGenomeSize = GenomeMatches.Excess.Length + GenomeMatches.RightDisjoint.Length;
                    }

                    break;

                // if the left is more fit and the excess belongs to the left inherit the excess and the left disjoints
                case FitnessState.LeftMoreFit:

                    inheritWholeExcess = !rightExcess;

                    if (inheritWholeExcess)
                    {
                        additionalGenomeSize = GenomeMatches.Excess.Length + GenomeMatches.LeftDisjoint.Length;
                    }

                    break;

                // if both are equally fit randomly inherit excess and disjoint genes
                case FitnessState.EqualFitness:
                    inheritRandomExcess = true;
                    inheritWholeExcess  = false;

                    // determine the max disjoint to inherit
                    if (Helpers.Random.NextUDouble() >= 0.5d && GenomeMatches.LeftDisjoint.Length > 0)
                    {
                        amountOfDisjointGenesToInherit = Helpers.Random.Next(0, GenomeMatches.LeftDisjoint.Length);
                    }
                    else if (GenomeMatches.RightDisjoint.Length > 0)
                    {
                        amountOfDisjointGenesToInherit = Helpers.Random.Next(0, GenomeMatches.RightDisjoint.Length);
                    }

                    amountOfExcessGenesToInherit = Helpers.Random.Next(0, GenomeMatches.Excess.Length + 1);

                    additionalGenomeSize = amountOfExcessGenesToInherit + amountOfDisjointGenesToInherit;

                    break;
                }
            }

            // divide the length by 2 since the array scheme holds both left and right aligned genes
            int startingIndex = GenomeMatches.Aligned.Length >> 1;

            // becuase we do not know the

            IInnovation[] result = new IInnovation[startingIndex + additionalGenomeSize];

            Span <IInnovation> newGenome = new(result);

            // get the rolls for the entire genome at once to avoid costly semaphore hits
            double[] rolls = Helpers.Random.NextUDoubleArray(newGenome.Length).Result;

            for (int i = 0; i < startingIndex; i++)
            {
                // randomly select genes
                if (rolls[i] > 0.5d)
                {
                    // select the left gene
                    newGenome[i] = GenomeMatches.Aligned[i << 1];
                    // left right left right left right
                    //  0      1    2    3     4    5
                    // left = i * 2
                }
                else
                {
                    // select the right gene
                    newGenome[i] = GenomeMatches.Aligned[(i << 1) + 1];
                    // left right left right left right
                    //  0      1    2    3     4    5
                    // right = i * 2 + 1
                }
            }

            // now that we have inserted all of the randomly chosen aligned genes we should add all of the excess and disjoint(if we determined earlier that it's appropriate

            //


            // copy the excess over to the destination array, we dont have to figure out who it belongs to yet becuase we only get 1 parents excess form the align genes method
            if (inheritWholeExcess)
            {
                // the size of the destination array has already been assigned so we dont have to resize and carve out another coiontiguous block of memory for the array
                Span <IInnovation> excess = new(GenomeMatches.Excess);
                excess.CopyTo(newGenome.Slice(startingIndex, excess.Length));

                // now copy over the disjointed values
                if (rightExcess)
                {
                    Span <IInnovation> disjointed = new(GenomeMatches.RightDisjoint);
                    disjointed.CopyTo(newGenome.Slice(startingIndex + excess.Length));
                }
                else
                {
                    Span <IInnovation> disjointed = new(GenomeMatches.LeftDisjoint);
                    disjointed.CopyTo(newGenome.Slice(startingIndex + excess.Length));
                }
            }
            else if (inheritRandomExcess)
            {
                // since we should inherit random genes from both parents start off by inheriting the whole excess
                Span <IInnovation> excess = new(GenomeMatches.Excess);

                for (int i = 0; i < amountOfExcessGenesToInherit; i++)
                {
                    newGenome[i + startingIndex] = excess[(i + Helpers.Random.Next(0, 101)) % amountOfExcessGenesToInherit];
                }

                int index = startingIndex + amountOfExcessGenesToInherit;

                // now randomly inherit excess genes
                for (int i = 0; i < amountOfDisjointGenesToInherit; i++)
                {
                    if (Helpers.Random.NextUDouble() >= 0.5d)
                    {
                        // left
                        if (GenomeMatches.LeftDisjoint.Length - 1 > i)
                        {
                            newGenome[index++] = GenomeMatches.LeftDisjoint[i];
                        }
                        else if (GenomeMatches.RightDisjoint.Length - 1 > i)
                        {
                            newGenome[index++] = GenomeMatches.RightDisjoint[i];
                        }
                    }
                    else
                    {
                        // right
                        if (GenomeMatches.RightDisjoint.Length - 1 > i)
                        {
                            newGenome[index++] = GenomeMatches.RightDisjoint[i];
                        }
                        else if (GenomeMatches.LeftDisjoint.Length - 1 > i)
                        {
                            newGenome[index++] = GenomeMatches.LeftDisjoint[i];
                        }
                    }
                }
            }

            return(result);
        }
Exemplo n.º 4
0
 /// <summary>
 /// Hashes the provided innovation so that it can be compared with others in the genome
 /// </summary>
 /// <param name="innovation"></param>
 /// <returns></returns>
 public string Hash(IInnovation innovation) => Hash(innovation.InputNode, innovation.OutputNode);
Exemplo n.º 5
0
 /// <summary>
 /// Returns exception:
 /// <code>
 /// Circular innovation Id(12) From(3) -> To(1). Innovations can not input from nodes above them in the network or output to nodes that are below them in the network.
 /// </code>
 /// </summary>
 /// <param name="innovation"></param>
 /// <returns></returns>
 public static Exception CircularInnovationReference(IInnovation innovation)
 {
     return(new StackOverflowException($"Circular innovation Id({innovation?.Id}) From({innovation?.InputNode}) -> To({innovation?.OutputNode}). Innovations can not input from nodes above them in the network or output to nodes that are below them in the network."));
 }