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); }
/** * @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; }
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(); } }
public void AddConnectionGene(ConnectionGene gene) { Connections.Add(gene.Innovation, gene); }
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); }
/// <summary> /// Add Connection Gene /// </summary> /// <param name="connection">Connection</param> public void AddConnectionGene(ConnectionGene connection) { Connections[connection.InnovationId] = connection; }
/// <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); }