public void AddConnectionMutation(Random r)
        {
            int      listSize = Nodes.Count;
            NodeGene node1    = Nodes[Random.Range(0, listSize)];
            NodeGene node2    = Nodes[Random.Range(0, listSize)];

            bool reversed = false;

            if (node1.GetType().Equals(NodeGene.NodeType.HIDDEN) && node2.GetType().Equals(NodeGene.NodeType.INPUT))
            {
                reversed = true;
            }
            else if (node1.GetType().Equals(NodeGene.NodeType.OUTPUT) && node2.GetType().Equals(NodeGene.NodeType.HIDDEN))
            {
                reversed = true;
            }
            else if (node1.GetType().Equals(NodeGene.NodeType.OUTPUT) && node2.GetType().Equals(NodeGene.NodeType.INPUT))
            {
                reversed = true;
            }

            bool connectionExists = false;

            foreach (ConnectionGene con in Connections.Values)
            {
                if (con.InNode == node1.ID && con.OutNode == node2.ID)
                {
                    connectionExists = true;
                    break;
                }
                else if (con.InNode == node2.ID && con.OutNode == node1.ID)
                {
                    connectionExists = true;
                    break;
                }
            }
            if (connectionExists)
            {
                return;
            }

            ConnectionGene newCon = new ConnectionGene(reversed ? node2.ID : node1.ID, reversed ? node1.ID : node2.ID, Random.Range(0f, 1f), true, 0);

            Connections.Add(newCon.Innovation, newCon);
        }
        public void AddNodeMutation(Counter innovation)
        {
            int            listSize = Connections.Count;
            ConnectionGene con      = Connections[Random.Range(0, listSize)];

            NodeGene inNode  = Nodes[con.InNode];
            NodeGene outNode = Nodes[con.OutNode];

            con.Expressed = false;

            NodeGene       newNode  = new NodeGene(NodeGene.NodeType.HIDDEN, Nodes.Count);
            ConnectionGene inToNew  = new ConnectionGene(inNode.ID, newNode.ID, 1f, true, innovation.GetInnovation());
            ConnectionGene newToOut = new ConnectionGene(newNode.ID, outNode.ID, con.Weight, true, innovation.GetInnovation());

            Nodes.Add(newNode.ID, newNode);
            Connections.Add(inToNew.Innovation, inToNew);
            Connections.Add(newToOut.Innovation, newToOut);
        }
Example #3
0
        /**
         * @param parent1   More fit parent
         * @param parent2   Less fit parent
         * Operating on a Genome object
         */
        public void Crossover(Genome parent1, Genome parent2)
        {
            // Genome child = new Genome();

            foreach (NodeGene parentNode in parent1.Nodes.Values)
            {
                AddNodeGene(parentNode.Copy());
            }
            foreach (ConnectionGene parentNode in parent1.Connections.Values)
            {
                if (parent2.Connections.ContainsValue(parentNode)) // matching gene
                {
                    ConnectionGene childConGene = (Random.Range(0f, 1f) >= 0.5) ? parentNode.Copy() : parent2.Connections[parentNode.Innovation].Copy();
                    AddConnectionGene(childConGene);
                }
                else // disjoint or excess gene
                {
                    ConnectionGene childConGene = parentNode.Copy();
                    AddConnectionGene(childConGene);
                }
            }
            //return child;
        }
Example #4
0
        private Neuron.ActivationType _activationType;                                          // ActivationType

        public NeuralNetwork(Genome genome, Neuron.ActivationType activationType = Neuron.ActivationType.SIGMOID, bool bias = true, int timeOut = 1000)
        {
            _activationType     = activationType;
            _bias               = bias;
            _timeOut            = timeOut;
            _inputIds           = new List <int>();
            _outputIds          = new List <int>();
            _neurons            = new Dictionary <int, Neuron>();
            _unprocessedNeurons = new List <Neuron>();
            Genome              = genome;
            Fitness             = 0f;

            // Fill Neurons, Input & Outputs Ids w/ Nodes in Genome
            foreach (int nodeId in genome.Nodes.Keys)
            {
                NodeGene node   = genome.Nodes[nodeId];
                Neuron   neuron = null;

                // Input & Output Node
                if (node.Type == NodeGene.TYPE.INPUT)
                {
                    neuron = new Neuron(Neuron.NeuronType.INPUT, _activationType, false); // No bias on Input Node
                    neuron.AddInputConnection();
                    _inputIds.Add(nodeId);
                }
                else if (node.Type == NodeGene.TYPE.OUTPUT)
                {
                    neuron = new Neuron(Neuron.NeuronType.OUTPUT, _activationType, _bias);
                    _outputIds.Add(nodeId);
                }
                else
                {
                    neuron = new Neuron(Neuron.NeuronType.HIDDEN, _activationType, _bias);
                }

                // Add Neuron to the Network
                _neurons.Add(nodeId, neuron);
            }
            _inputIds.Sort();
            _outputIds.Sort();

            // Add Genome Connections to Neurons
            foreach (int connectionId in genome.Connections.Keys)
            {
                ConnectionGene connection = genome.Connections[connectionId];

                // Ignore Disabled Nodes
                if (!connection.IsEnable)
                {
                    continue;
                }

                // Add Output Connection to the Neuron of the emitting Node
                Neuron emittingNeuron = _neurons[connection.InNode];
                emittingNeuron.AddOutputConnection(connection.OutNode, connection.Weight);

                // Add Input Connection to the Neuron of the receiving Node
                Neuron receivingNeuron = _neurons[connection.OutNode];
                receivingNeuron.AddInputConnection();
            }
        }
Example #5
0
 public void AddConnectionGene(ConnectionGene gene)
 {
     Connections.Add(gene.Innovation, gene);
 }
Example #6
0
        public static float CompatibilityDistance(Genome genome1, Genome genome2, float c1, float c2, float c3)
        {
            int   matchingGenes         = 0;
            int   disjointGenes         = 0;
            int   excessGenes           = 0;
            float weightDifference      = 0;
            float avgWeightDiff         = 0;
            float compatibilityDistance = 0;

            int highestNodeInnovation1 = genome1.Nodes.Keys.Max(); // find largest innovation number
            int highestNodeInnovation2 = genome2.Nodes.Keys.Max();
            int indicesNode            = Mathf.Max(highestNodeInnovation1, highestNodeInnovation2);

            for (int i = 0; i <= indicesNode; i++)
            {                   // loop through genes -> i is innovation numbers
                NodeGene node1 = genome1.Nodes[i];
                NodeGene node2 = genome2.Nodes[i];
                if (node1 != null && node2 != null)
                {
                    // both genomes has the gene w/ this innovation number
                    matchingGenes++;
                }
                else if (node1 == null && node2 != null && highestNodeInnovation1 > i)
                {
                    // genome 1 lacks gene, genome 2 has gene, genome 1 has more genes w/ higher innovation numbers
                    disjointGenes++;
                }
                else if (node1 != null && node2 == null && highestNodeInnovation2 > i)
                {
                    // genome 2 lacks gene, genome 1 has gene, genome 2 has more genes w/ higher innovation numbers
                    disjointGenes++;
                }
                else if (node1 == null && node2 != null && highestNodeInnovation1 < i)
                {
                    // genome 1 lacks gene, genome 2 has gene, genome 2 has more genes w/ higher innovation numbers
                    excessGenes++;
                }
                else if (node1 != null && node2 == null && highestNodeInnovation2 < i)
                {
                    // genome 2 lacks gene, genome 1 has gene, genome 1 has more genes w/ higher innovation numbers
                    excessGenes++;
                }
            }

            int highestConnectionInnovation1 = genome1.Connections.Keys.Max(); // find largest innovation number
            int highestConnectionInnovation2 = genome2.Connections.Keys.Max();
            int indicesCon = Mathf.Max(highestConnectionInnovation1, highestConnectionInnovation2);

            for (int i = 0; i <= indicesCon; i++)
            {                   // loop through genes -> i is innovation numbers
                ConnectionGene connection1 = genome1.Connections[i];
                ConnectionGene connection2 = genome2.Connections[i];
                if (connection1 != null && connection2 != null)
                {
                    // both genomes has the gene w/ this innovation number
                    matchingGenes++;
                    weightDifference += Mathf.Abs(connection1.Weight - connection2.Weight);
                }
                else if (connection1 == null && connection2 != null && highestConnectionInnovation1 > i)
                {
                    // genome 1 lacks gene, genome 2 has gene, genome 1 has more genes w/ higher innovation numbers
                    disjointGenes++;
                }
                else if (connection1 != null && connection2 == null && highestConnectionInnovation2 > i)
                {
                    // genome 2 lacks gene, genome 1 has gene, genome 2 has more genes w/ higher innovation numbers
                    disjointGenes++;
                }
                else if (connection1 == null && connection2 != null && highestConnectionInnovation1 < i)
                {
                    // genome 1 lacks gene, genome 2 has gene, genome 1 has more genes w/ higher innovation numbers
                    excessGenes++;
                }
                else if (connection1 != null && connection2 == null && highestConnectionInnovation2 < i)
                {
                    // genome 2 lacks gene, genome 1 has gene, genome 2 has more genes w/ higher innovation numbers
                    excessGenes++;
                }
            }
            avgWeightDiff = weightDifference / matchingGenes;
            float N = 1; // number of genes in largest parent, 1 if less than 20 genes

            compatibilityDistance = excessGenes * c1 / N + disjointGenes * c2 / N + avgWeightDiff * c3;

            return(compatibilityDistance);
        }
Example #7
0
 /// <summary>
 /// Add Connection Gene
 /// </summary>
 /// <param name="connection">Connection</param>
 public void AddConnectionGene(ConnectionGene connection)
 {
     Connections[connection.InnovationId] = connection;
 }
Example #8
0
        /// <summary>
        /// Add a new Connection between 2 Random Nodes
        /// </summary>
        /// <param name="r">Random</param>
        /// <param name="connectionInnovationCounter">Connection Innovation Counter</param>
        /// <param name="maxTries">Max Tries to attemp Mutation</param>
        /// <returns>Success</returns>
        public bool AddConnectionMutation(Random r, InnovationCounter connectionInnovationCounter, int maxTries = 10)
        {
            bool success = false;

            // Try maxTries times
            for (int tries = 0; tries < maxTries && !success; tries++)
            {
                // Get 2 Random Nodes & a Random Weight
                List <int> nodeInnovationIds = new List <int>(Nodes.Keys);
                NodeGene   node1             = Nodes[nodeInnovationIds[r.Next(nodeInnovationIds.Count)]];
                NodeGene   node2             = Nodes[nodeInnovationIds[r.Next(nodeInnovationIds.Count)]];

                // Sigmoid Weights
                // float weight = (float)r.NextDouble() * 2f - 1f;

                // Tanh Weights
                // float weight = UnityEngine.Random.Range(-0.5f, 0.5f);

                // Config Weights
                float weight = UnityEngine.Random.Range(NewWeightRange.x, NewWeightRange.y);

                // Is Reversed ?
                if ((node1.Type == NodeGene.TYPE.HIDDEN && node2.Type == NodeGene.TYPE.INPUT) ||
                    (node1.Type == NodeGene.TYPE.OUTPUT && node2.Type == NodeGene.TYPE.HIDDEN) ||
                    (node1.Type == NodeGene.TYPE.OUTPUT && node2.Type == NodeGene.TYPE.INPUT))
                {
                    NodeGene swap = node1;
                    node1 = node2;
                    node2 = swap;
                }

                // Is Connection Impossible ?
                if ((node1.Type == NodeGene.TYPE.INPUT && node2.Type == NodeGene.TYPE.INPUT) ||
                    (node1.Type == NodeGene.TYPE.OUTPUT && node2.Type == NodeGene.TYPE.OUTPUT) ||
                    (node1 == node2))
                {
                    continue;
                }

                // Does Connection already exists ?
                bool connectionExists = false;
                foreach (ConnectionGene c in Connections.Values)
                {
                    if ((c.InNode == node1.Id && c.OutNode == node2.Id) ||
                        (c.InNode == node2.Id && c.OutNode == node1.Id))
                    {
                        connectionExists = true;
                        break;
                    }
                }
                if (connectionExists)
                {
                    continue;
                }

                // Circular structure ?
                bool       connectionImpossible = false;
                List <int> nodeIds     = new List <int>();                  // Node that need output from node2
                List <int> nodeToCheck = new List <int>();                  // Nodes to check
                foreach (int connectionId in Connections.Keys)              // Get all Connections w/ outNode == node2
                {
                    ConnectionGene connection = Connections[connectionId];
                    if (connection.InNode == node2.Id)                      // Connection comes from node2
                    {
                        nodeIds.Add(connection.OutNode);
                        nodeToCheck.Add(connection.OutNode);
                    }
                }
                while (nodeToCheck.Count > 0)                               // Get all Connections w/ outNode == nodeToCheck
                {
                    int nodeId = nodeToCheck[0];
                    foreach (int connectionId in Connections.Keys)
                    {
                        ConnectionGene connection = Connections[connectionId];
                        if (connection.InNode == nodeId)                    // Connection comes from nodeToCheck
                        {
                            nodeIds.Add(connection.OutNode);
                            nodeToCheck.Add(connection.OutNode);
                        }
                    }
                    nodeToCheck.RemoveAt(0);
                }
                foreach (int i in nodeIds)                                  // Loop through all Node Ids
                {
                    if (i == node1.Id)                                      // If one of the Node == node1 => Connection is Impossible
                    {
                        connectionImpossible = true;
                        break;
                    }
                }
                if (connectionImpossible)
                {
                    continue;
                }

                // Add new Connection
                ConnectionGene newConnection = new ConnectionGene(
                    node1.Id,
                    node2.Id,
                    weight,
                    true,
                    connectionInnovationCounter.GetNewInnovationNumber()
                    );
                Connections.Add(newConnection.InnovationId, newConnection);
                success = true;
            }

            return(success);
        }