/// <summary> /// Add a new Node to a Random Connection /// </summary> /// <param name="r">Random</param> /// <param name="connectionInnovationCounter">Connection Innovation Counter</param> /// <param name="nodeInnovationCounter">Node Innovation Counter</param> public void AddNodeMutation(Random r, InnovationCounter connectionInnovationCounter, InnovationCounter nodeInnovationCounter) { // Get enabled Connections List <ConnectionGene> enabledConnections = new List <ConnectionGene>(); foreach (ConnectionGene c in Connections.Values) { if (c.IsEnable) { enabledConnections.Add(c); } } if (enabledConnections.Count == 0) { return; } // Get a Random Connection ConnectionGene connection = enabledConnections[r.Next(enabledConnections.Count)]; NodeGene inNode = Nodes[connection.InNode]; NodeGene outNode = Nodes[connection.OutNode]; // Disbale Old Connection connection.IsEnable = false; // Create a node w/ IN & OUT Connection to replace old Connection NodeGene newNode = new NodeGene(NodeGene.TYPE.HIDDEN, nodeInnovationCounter.GetNewInnovationNumber()); ConnectionGene inToNew = new ConnectionGene(inNode.Id, newNode.Id, 1f, true, connectionInnovationCounter.GetNewInnovationNumber()); // Weight of 1 ConnectionGene newToOut = new ConnectionGene(newNode.Id, outNode.Id, connection.Weight, true, connectionInnovationCounter.GetNewInnovationNumber()); // Weight of old Connection // Add Node & Connections to the Genome Nodes.Add(newNode.Id, newNode); Connections.Add(inToNew.InnovationId, inToNew); Connections.Add(newToOut.InnovationId, newToOut); }
private string _mutationLogs = ""; // Mutation Logs public EvaluatorRT(RTNEATConfig config, Genome startingGenome, InnovationCounter nodeInnovation, InnovationCounter connectionInnovation) { _config = config; _nodeInnovation = nodeInnovation; _connectionInnovation = connectionInnovation; _currentPop = 0; _genomes = new List <Genome>(); for (int i = 0; i < _config.startPopulation; ++i) { AddGenomeToList(Genome.GenomeRandomWeights(startingGenome, _r)); } BestFitness = -1f; BestGenome = null; }
private string _mutationLogs = ""; // Mutation Logs public Evaluator(NEATConfig config, Genome startingGenome, InnovationCounter nodeInnovation, InnovationCounter connectionInnovation) { _config = config; GenerationNumber = 0; _nodeInnovation = nodeInnovation; _connectionInnovation = connectionInnovation; _genomes = new List <Genome>(); for (int i = 0; i < _config.populationSize; ++i) { _genomes.Add(Genome.GenomeRandomWeights(startingGenome, _r)); } _nextEvaluationGenomes = new List <Genome>(); _species = new List <Species>(); _genomesSpecies = new Dictionary <Genome, Species>(); BestFitness = -1f; BestGenome = null; }
/// <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); }