Example #1
0
        /// <inheritdoc/>
        public void PerformOperation(EncogRandom rnd, IGenome[] parents, int parentIndex,
                IGenome[] offspring, int offspringIndex)
        {
            IArrayGenome parent = (IArrayGenome)parents[parentIndex];
            offspring[offspringIndex] = this.owner.Population.GenomeFactory.Factor();
            IArrayGenome child = (IArrayGenome)offspring[offspringIndex];

            child.Copy(parent);

            int length = parent.Size;
            int iswap1 = (int)(rnd.NextDouble() * length);
            int iswap2 = (int)(rnd.NextDouble() * length);

            // can't be equal
            if (iswap1 == iswap2)
            {
                // move to the next, but
                // don't go out of bounds
                if (iswap1 > 0)
                {
                    iswap1--;
                }
                else
                {
                    iswap1++;
                }

            }

            // make sure they are in the right order
            if (iswap1 > iswap2)
            {
                int temp = iswap1;
                iswap1 = iswap2;
                iswap2 = temp;
            }

            child.Swap(iswap1, iswap2);
        }
        /// <inheritdoc/>
        public void PerformOperation(EncogRandom rnd, IGenome[] parents, int parentIndex,
                IGenome[] offspring, int offspringIndex)
        {
            DoubleArrayGenome parent = (DoubleArrayGenome)parents[parentIndex];
            offspring[offspringIndex] = parent.Population.GenomeFactory.Factor();
            DoubleArrayGenome child = (DoubleArrayGenome)offspring[offspringIndex];

            for (int i = 0; i < parent.Size; i++)
            {
                double value = parent.Data[i];
                value += (perturbAmount - (rnd.NextDouble() * perturbAmount * 2));
                child.Data[i] = value;
            }
        }
        /// <inheritdoc />
        public override ProgramNode CreateNode(EncogRandom rnd, EncogProgram program,
                                               int depthRemaining, IList<EPLValueType> types)
        {
            int actualDepthRemaining = depthRemaining;

            if (rnd.NextDouble() > 0.5)
            {
                return _fullGenerator.CreateNode(rnd, program,
                                                actualDepthRemaining, types);
            }
            return _growGenerator.CreateNode(rnd, program,
                                             actualDepthRemaining, types);
        }
        /// <summary>
        /// Choose a parent to favor.
        /// </summary>
        /// <param name="rnd">Random generator.</param>
        /// <param name="mom">The mother.</param>
        /// <param name="dad">The father</param>
        /// <returns></returns>
        private NEATGenome FavorParent(EncogRandom rnd, NEATGenome mom, NEATGenome dad)
        {
            // first determine who is more fit, the mother or the father?
            // see if mom and dad are the same fitness
            if (Math.Abs(mom.Score - dad.Score) < EncogFramework.DefaultDoubleEqual)
            {
                // are mom and dad the same fitness
                if (mom.NumGenes == dad.NumGenes)
                {
                    // if mom and dad are the same fitness and have the same number
                    // of genes,
                    // then randomly pick mom or dad as the most fit.
                    if (rnd.NextDouble() > 0.5)
                    {
                        return mom;
                    }
                    return dad;
                }
                    // mom and dad are the same fitness, but different number of genes
                // favor the parent with fewer genes
                if (mom.NumGenes < dad.NumGenes)
                {
                    return mom;
                }
                return dad;
            }
            // mom and dad have different scores, so choose the better score.
            // important to note, better score COULD BE the larger or smaller
            // score.
            if (_owner.SelectionComparer.Compare(mom, dad) < 0)
            {
                return mom;
            }

            return dad;
        }
        /// <inheritdoc/>
        public void PerformOperation(EncogRandom rnd, IGenome[] parents,
                int parentIndex, IGenome[] offspring,
            int offspringIndex)
        {
            var mom = (NEATGenome)parents[parentIndex + 0];
            var dad = (NEATGenome)parents[parentIndex + 1];

            var best = FavorParent(rnd, mom, dad);
            var notBest = (best == mom) ? mom : dad;

            var selectedLinks = new List<NEATLinkGene>();
            var selectedNeurons = new List<NEATNeuronGene>();

            int curMom = 0; // current gene index from mom
            int curDad = 0; // current gene index from dad
            NEATLinkGene selectedGene = null;

            // add in the input and bias, they should always be here
            int alwaysCount = ((NEATGenome)parents[0]).InputCount
                    + ((NEATGenome)parents[0]).OutputCount + 1;
            for (int i = 0; i < alwaysCount; i++)
            {
                AddNeuronId(i, selectedNeurons, best, notBest);
            }

            while ((curMom < mom.NumGenes) || (curDad < dad.NumGenes))
            {
                NEATLinkGene momGene = null; // the mom gene object
                NEATLinkGene dadGene = null; // the dad gene object
                long momInnovation = -1;
                long dadInnovation = -1;

                // grab the actual objects from mom and dad for the specified
                // indexes
                // if there are none, then null
                if (curMom < mom.NumGenes)
                {
                    momGene = mom.LinksChromosome[curMom];
                    momInnovation = momGene.InnovationId;
                }

                if (curDad < dad.NumGenes)
                {
                    dadGene = dad.LinksChromosome[curDad];
                    dadInnovation = dadGene.InnovationId;
                }

                // now select a gene for mom or dad. This gene is for the baby
                if ((momGene == null) && (dadGene != null))
                {
                    if (best == dad)
                    {
                        selectedGene = dadGene;
                    }
                    curDad++;
                }
                else if ((dadGene == null) && (momGene != null))
                {
                    if (best == mom)
                    {
                        selectedGene = momGene;
                    }
                    curMom++;
                }
                else if (momInnovation < dadInnovation)
                {
                    if (best == mom)
                    {
                        selectedGene = momGene;
                    }
                    curMom++;
                }
                else if (dadInnovation < momInnovation)
                {
                    if (best == dad)
                    {
                        selectedGene = dadGene;
                    }
                    curDad++;
                }
                else if (dadInnovation == momInnovation)
                {
                    selectedGene = rnd.NextDouble() < 0.5f ? momGene : dadGene;
                    curMom++;
                    curDad++;
                }

                if (selectedGene != null)
                {
                    if (selectedLinks.Count == 0)
                    {
                        selectedLinks.Add(selectedGene);
                    }
                    else
                    {
                        if (selectedLinks[selectedLinks.Count - 1]
                                .InnovationId != selectedGene
                                .InnovationId)
                        {
                            selectedLinks.Add(selectedGene);
                        }
                    }

                    // Check if we already have the nodes referred to in
                    // SelectedGene.
                    // If not, they need to be added.
                    AddNeuronId(selectedGene.FromNeuronId, selectedNeurons,
                            best, notBest);
                    AddNeuronId(selectedGene.ToNeuronId, selectedNeurons,
                            best, notBest);
                }

            }

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

            // finally, create the genome
            var factory = (INEATGenomeFactory)_owner
                    .Population.GenomeFactory;
            var babyGenome = factory.Factor(selectedNeurons,
                    selectedLinks, mom.InputCount, mom.OutputCount);
            babyGenome.BirthGeneration = _owner.IterationNumber;
            babyGenome.Population = _owner.Population;
            babyGenome.SortGenes();

            offspring[offspringIndex] = babyGenome;
        }
        /// <summary>
        ///     Called for each node in the progrmam. If this is a const node, then
        ///     mutate it according to the frequency and sigma specified.
        /// </summary>
        /// <param name="rnd">Random number generator.</param>
        /// <param name="node">The node to mutate.</param>
        private void MutateNode(EncogRandom rnd, ProgramNode node)
        {
            if (node.Template == StandardExtensions.EXTENSION_CONST_SUPPORT)
            {
                if (rnd.NextDouble() < _frequency)
                {
                    ExpressionValue v = node.Data[0];
                    if (v.IsFloat)
                    {
                        double adj = rnd.NextGaussian()*_sigma;
                        node.Data[0] = new ExpressionValue(v.ToFloatValue()
                                                           + adj);
                    }
                }
            }

            foreach (ITreeNode n in node.ChildNodes)
            {
                var childNode = (ProgramNode) n;
                MutateNode(rnd, childNode);
            }
        }
        /// <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);
                    }
                }
            }
        }
        /// <inheritdoc/>
        public IList<NEATLinkGene> SelectLinks(EncogRandom rnd, NEATGenome genome)
        {
            IList<NEATLinkGene> result = new List<NEATLinkGene>();

            bool mutated = false;

            foreach (var linkGene in genome.LinksChromosome)
            {
                if (rnd.NextDouble() < _proportion)
                {
                    mutated = true;
                    result.Add(linkGene);
                }
            }

            if (!mutated)
            {
                int idx = rnd.Next(genome.LinksChromosome.Count);
                NEATLinkGene linkGene = genome.LinksChromosome[idx];
                result.Add(linkGene);
            }

            return result;
        }