コード例 #1
0
 /// <summary>
 /// Adds all innovations from another InnovationPool to end of Pool.
 /// </summary>
 /// <param name="pool">The other pool to add.</param>
 /// <returns>The last index of the new pool.</returns>
 public int AddRange(InnovationPool pool)
 {
     for (int i = 0; i < pool.Size(); i++)
     {
         Add(pool.FindById(i));
     }
     return(Size() - 1);
 }
コード例 #2
0
        public List <Genome> Reproduce(int expectedChildren, InnovationPool seenInnovations, List <Species> interBredSpecies, Random rando)
        {
            List <Genome> children  = new List <Genome>();
            bool          champDone = false;

            while (expectedChildren > 0)
            {
                if (!champDone && expectedChildren >= Const.ChampSurvivalThresh)
                {
                    children.Add(Fitness.Champion);
                    champDone = true;
                }
                else if (rando.NextDouble() < Const.MutateOnlyProbability || expectedChildren == 1)
                {
                    Genome child = new Genome(Genomes[rando.Next(Size())]);
                    Mutation.Mutate(child, seenInnovations, rando);
                    children.Add(child);
                }
                else
                {
                    Genome mother = Genomes[rando.Next(Size())];
                    Genome father = null;

                    if (rando.NextDouble() < Const.InterSpeciesBreedingProbability)
                    {
                        Species spec = SelectOtherSpecies(interBredSpecies, rando);
                        father = spec.Fitness.Champion;
                    }
                    else
                    {
                        father = Genomes[rando.Next(Size())];
                    }

                    Genome child = Mating.Mate(mother, father, rando);

                    //TODO: Add mother/father node checking criteria as well?
                    if (rando.NextDouble() >= Const.MateOnlyProbability ||
                        GenomeCompatibility.Compatibility(mother, father) == 0.0)
                    {
                        Mutation.Mutate(child, seenInnovations, rando);
                    }

                    children.Add(child);
                }

                expectedChildren--;
            }

            return(children);
        }
コード例 #3
0
        /// <summary>
        /// Mutates a genome by breaking a connection up into two separate connections.
        /// </summary>
        /// <param name="genome">The genome to be modified.</param>
        /// <param name="innovationsSeen">A list of previously seen innovations.</param>
        /// <param name="rando">A random number generator.</param>
        public static void MutateAddNode(Genome genome, InnovationPool innovationsSeen, Random rando)
        {
            List <Gene> possibleConnections = new List <Gene>(genome.Genes);

            possibleConnections.RemoveAll(x => x.Frozen || NodePool.FindById(x.link.InNode).Type == NodeType.BIAS);

            if (possibleConnections.Count == 0)
            {
                return;
            }

            //TODO: Note in original algorithm saying uniform distribution is not optimal here.
            Gene geneToSplit = possibleConnections[rando.Next(possibleConnections.Count)];

            geneToSplit.Frozen = true;

            ActivationStyle       style      = ActivationFunctions.ChooseActivationStyle(rando);
            InnovationInformation innovation = new InnovationInformation(geneToSplit.link, style);

            int firstConId  = -1;
            int secondConId = -1;

            int registeredInnovationId = innovationsSeen.FindByInnovation(innovation);

            if (registeredInnovationId == -1)
            {
                int newNodeId = NodePool.Add(new NodeInformation(NodeType.HIDDEN, style));

                ConnectionInformation firstConnect = new ConnectionInformation(geneToSplit.link.InNode, newNodeId);
                firstConId = ConnectionPool.Add(firstConnect);

                ConnectionInformation secondConnect = new ConnectionInformation(newNodeId, geneToSplit.link.OutNode);
                secondConId = ConnectionPool.Add(secondConnect);

                innovation.NewNodeDetails.NewNodeId          = newNodeId;
                innovation.NewNodeDetails.FirstConnectionId  = firstConId;
                innovation.NewNodeDetails.SecondConnectionId = secondConId;
                innovationsSeen.Add(innovation);
            }
            else
            {
                InnovationInformation registeredInnovation = innovationsSeen.FindById(registeredInnovationId);
                firstConId  = registeredInnovation.NewNodeDetails.FirstConnectionId;
                secondConId = registeredInnovation.NewNodeDetails.SecondConnectionId;
            }

            genome.Genes.Add(new Gene(ConnectionPool.FindById(firstConId), firstConId, 1.0, false));
            genome.Genes.Add(new Gene(ConnectionPool.FindById(secondConId), secondConId, geneToSplit.Weight, false));
        }
コード例 #4
0
        /// <summary>
        /// Randomly mutates a genome.
        /// This is a conglomerate of mutations.
        /// </summary>
        /// <param name="genome">The genome to mutate.</param>
        /// <param name="innovationsSeen">A list of previously seen innovations.</param>
        /// <param name="rando">A random number generator.</param>
        public static void Mutate(Genome genome, InnovationPool innovationsSeen, Random rando)
        {
            MutationStyle style = ChooseMutationStyle(rando);

            Genome original = new Genome(genome);

            switch (style)
            {
            case MutationStyle.AddNode:
                MutateAddNode(genome, innovationsSeen, rando);
                break;

            case MutationStyle.AddConnection:
                MutateAddConnection(genome, innovationsSeen, rando);
                break;

            case MutationStyle.TryAllNonStructural:
                MutateTryAllNonStructural(genome, rando);
                break;

            default:
                throw new Exception("Mutate did not catch a valid MutationStyle.");
            }
        }
コード例 #5
0
        /// <summary>
        /// Mutates a given genome by adding a connection.
        /// Connection is guaranteed to not be 'into' a sensor or bias.
        /// </summary>
        /// <param name="genome">The genome to be modified.</param>
        /// <param name="innovationsSeen">A list of previously seen innovations.</param>
        /// <param name="rando">A random number generator.</param>
        public static void MutateAddConnection(Genome genome, InnovationPool innovationsSeen, Random rando)
        {
            //TODO: I'm getting the node information, but I only need that to construct allNodesNotInput...

            Dictionary <int, NodeInformation> allNodes         = genome.GetAllNodeInformation(true);
            Dictionary <int, NodeInformation> allNodesNotInput = new Dictionary <int, NodeInformation>(allNodes);

            //TODO: Witnessed a bug where allNodes.Count == 0.
            //      Could be a node where there are only frozen links connecting.

            foreach (var id in allNodesNotInput.Where(kvp => kvp.Value.IsInput()).ToList())
            {
                allNodesNotInput.Remove(id.Key);
            }

            //TODO: Gotta be a better way than a tryCount...
            int tryCount   = 0;
            int nodeFromId = -1;
            int nodeToId   = -1;

            while (tryCount < 20)
            {
                nodeFromId = allNodes.Keys.ToList()[rando.Next(allNodes.Count)];
                nodeToId   = allNodesNotInput.Keys.ToList()[rando.Next(allNodesNotInput.Count)];

                if (!genome.ContainsConnection(nodeFromId, nodeToId))
                {
                    break;
                }

                tryCount++;
            }

            if (tryCount == 20)
            {
                return;
            }

            ConnectionInformation connectInfo = new ConnectionInformation(nodeFromId, nodeToId);
            InnovationInformation innovation  = new InnovationInformation(connectInfo);

            int connectId = -1;
            //TODO: Pull inital weight setting out of here.
            double weight = rando.NextDouble() * 2.0 - 1.0;

            int registeredInnovationId = innovationsSeen.FindByInnovation(innovation);

            if (registeredInnovationId == -1)
            {
                connectId = ConnectionPool.Add(connectInfo);

                innovation.NewConnectionDetails.ConnectionId = connectId;
                innovationsSeen.Add(innovation);
            }
            else
            {
                connectId = innovationsSeen.FindById(registeredInnovationId).NewConnectionDetails.ConnectionId;
            }

            genome.Genes.Add(new Gene(ConnectionPool.FindById(connectId), connectId, weight, false));
        }