public void GetConnectionInnovationNumber_Test() { GeneCounter connectionCounter = new GeneCounter(10); //Check the amount before Assert.AreEqual(1, mutationLog.ConnectionMutations.Count); //Insert an existing connection int existingConnection = mutationLog.GetConnectionInnovationNumber(1, 2, connectionCounter); //Check the amount after getting the existing connection Assert.AreEqual(1, mutationLog.ConnectionMutations.Count); Assert.AreEqual(1, existingConnection); //Insert new connection int newConnection = mutationLog.GetConnectionInnovationNumber(2, 1, connectionCounter); //Check the amount after the inserting the new connection Assert.AreEqual(2, mutationLog.ConnectionMutations.Count); Assert.AreEqual(10, newConnection); //Insert new connection again newConnection = mutationLog.GetConnectionInnovationNumber(2, 1, connectionCounter); //Check the amount after the inserting the new connection Assert.AreEqual(2, mutationLog.ConnectionMutations.Count); Assert.AreEqual(10, newConnection); }
/// <summary> /// Create the start genome /// </summary> private void SetStartGenome() { _nodeCounter = new GeneCounter(0); _connectionCounter = new GeneCounter(0); _startGenome = new Genome(); //5 input nodes + 1 bias node _startGenome.AddNodeGene(new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.INPUT, 0f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID)); _startGenome.AddNodeGene(new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.INPUT, 0f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID)); _startGenome.AddNodeGene(new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.INPUT, 0f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID)); _startGenome.AddNodeGene(new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.INPUT, 0f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID)); _startGenome.AddNodeGene(new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.INPUT, 0f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID)); _startGenome.AddNodeGene(new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.INPUT, 0f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID)); //OutputNodes _startGenome.AddNodeGene(new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.OUTPUT, 1f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID)); _startGenome.AddNodeGene(new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.OUTPUT, 1f, ActivationFunctionHelper.Function.STEEPENED_SIGMOID)); //Add connections to first output nde _startGenome.AddConnectionGene(new ConnectionGene(0, 6, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber())); _startGenome.AddConnectionGene(new ConnectionGene(1, 6, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber())); _startGenome.AddConnectionGene(new ConnectionGene(2, 6, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber())); _startGenome.AddConnectionGene(new ConnectionGene(3, 6, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber())); _startGenome.AddConnectionGene(new ConnectionGene(4, 6, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber())); _startGenome.AddConnectionGene(new ConnectionGene(5, 6, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber())); //Connection to second ouztputNode _startGenome.AddConnectionGene(new ConnectionGene(0, 7, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber())); _startGenome.AddConnectionGene(new ConnectionGene(1, 7, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber())); _startGenome.AddConnectionGene(new ConnectionGene(2, 7, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber())); _startGenome.AddConnectionGene(new ConnectionGene(3, 7, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber())); _startGenome.AddConnectionGene(new ConnectionGene(4, 7, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber())); _startGenome.AddConnectionGene(new ConnectionGene(5, 7, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber())); }
public void CreateInitialPopulation(Genome startingGenome, GeneCounter nodeInnovationCounter, GeneCounter connectionInnovationCounter, int populationSize, bool randomizeWeights) { _generation = 0; _nodeInnovationCounter = nodeInnovationCounter; _connectionInnovationCounter = connectionInnovationCounter; _populationSize = populationSize; _mutationLog = new MutationLog(); _agents = new List <AgentObject>(); _species = new List <Species>(); for (int i = 0; i < _populationSize; i++) { Genome randomGenome = new Genome(startingGenome); if (randomizeWeights) { foreach (ConnectionGene con in randomGenome.Connections.Values) { con.Weight = Random.Range(-1f, 1f); } } AgentObject agent = _callback.InitNewAgent(this, randomGenome); _agents.Add(agent); } PlaceAgentInSpecies(_agents, _species); //Notify the callback if not existing if (_callback != null) { _callback.AgentsInitializedCallback(_agents, _species, _generation); } }
/// <summary> /// Create the start genome /// </summary> private void SetStartGenome() { _nodeCounter = new GeneCounter(0); _connectionCounter = new GeneCounter(0); _startGenome = new Genome(); int amountPlayerInputs = PlayerController.GetAmountOfInputs(_levelViewWidht, _levelViewHeight); List <NodeGene> tmpInputNodes = new List <NodeGene>(); //Crate input nodes for (int i = 0; i < amountPlayerInputs; i++) { NodeGene node = new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.INPUT, 0f, ActivationFunctionHelper.Function.SIGMOID); _startGenome.AddNodeGene(node); tmpInputNodes.Add(node); } //Create output nodes NodeGene outputNode1 = new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.OUTPUT, 1f, ActivationFunctionHelper.Function.SIGMOID); NodeGene outputNode2 = new NodeGene(_nodeCounter.GetNewNumber(), NodeGeneType.OUTPUT, 1f, ActivationFunctionHelper.Function.SIGMOID); _startGenome.AddNodeGene(outputNode1); _startGenome.AddNodeGene(outputNode2); //Create connections for (int i = 0; i < amountPlayerInputs; i++) { _startGenome.AddConnectionGene(new ConnectionGene(tmpInputNodes[i].ID, outputNode1.ID, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber())); _startGenome.AddConnectionGene(new ConnectionGene(tmpInputNodes[i].ID, outputNode2.ID, Random.Range(-1f, 1f), true, _connectionCounter.GetNewNumber())); } }
// Use this for initialization void Start() { Genome parent3GenomeSimple = new Genome(); //Create the input nodes parent3GenomeSimple.AddNodeGene(new NodeGene(1, NodeGeneType.INPUT, 0f)); parent3GenomeSimple.AddNodeGene(new NodeGene(2, NodeGeneType.INPUT, 0f)); parent3GenomeSimple.AddNodeGene(new NodeGene(3, NodeGeneType.INPUT, 0f)); //Create the output node parent3GenomeSimple.AddNodeGene(new NodeGene(4, NodeGeneType.OUTPUT, 1f)); //Create connections parent3GenomeSimple.AddConnectionGene(new ConnectionGene(1, 4, 1.0, true, 1)); parent3GenomeSimple.AddConnectionGene(new ConnectionGene(2, 4, 1.0, true, 2)); parent3GenomeSimple.AddConnectionGene(new ConnectionGene(3, 4, 1.0, true, 3)); //Init the connection gene counter with 11 connectionCounter = new GeneCounter(4); nodeCounter = new GeneCounter(5); manager.Callback = this; manager.CreateInitialPopulation(parent3GenomeSimple, nodeCounter, connectionCounter, 100); }
/// <summary> /// Get an InnovationNumber for the connection between the given nodes. /// If there is already and entry for the connection, the existing InnovationNumber will be returned /// If it is a new connection, a new number will be generated with the connectionMutationCounter and after that directly stored /// </summary> /// <param name="inNodeID">the in node of the new connection</param> /// <param name="outNodeID">the out node of the new connection</param> /// <param name="connectionMutationCounter">GeneCounter to generate a new number if necessary</param> /// <returns>the InnovationNumber for the connection</returns> public int GetConnectionInnovationNumber(int inNodeID, int outNodeID, GeneCounter connectionMutationCounter) { int innovationNumber = IsConnectionExisting(inNodeID, outNodeID); //If node is existing return the value if (innovationNumber != -1) { return(innovationNumber); } innovationNumber = connectionMutationCounter.GetNewNumber(); //Store new mutation AddConnectionMutation(inNodeID, outNodeID, innovationNumber); return(innovationNumber); }
/* * * /// <summary> * /// Get an ID for the a new node that will be splaced between the given connection. * /// If there is already an entry for the node, the existing id will be returned. * /// If it is a new node a new numer will be generated with the GeneCounter and after that directly stored. * /// </summary> * /// <param name="connectionInnovationNumber">innovationNumber of the conenction that will be splitted</param> * /// <param name="nodeMutationCounter">to generate a new node ID if necessary</param> * /// <returns>an ID for the node</returns> * public int GetNodeID(int connectionInnovationNumber, GeneCounter nodeMutationCounter) * { * int nodeID = IsNodeExisting(connectionInnovationNumber); * * //If node is existing return the value * if (nodeID != -1) return nodeID; * * nodeID = nodeMutationCounter.GetNewNumber(); * * //Add node to the list * AddNodeMutation(connectionInnovationNumber, nodeID); * * return nodeID; * * } * */ /// <summary> /// Get an id for a new node. /// If the mutation has already occured, an existing id will be returned. /// If the mutation is new, a new id will be generated and stored in the log /// </summary> /// <param name="connectionInnovationNumber">the innovation number of the splitted connection</param> /// <param name="nodeIDs">a list with all node ids' of the genome</param> /// <param name="nodeMutationCounter">a node mutation counter to generate a new id if necessary</param> /// <returns>an id for the node</returns> public int GetNodeID(int connectionInnovationNumber, List <int> nodeIDs, GeneCounter nodeMutationCounter) { List <int> existingNodeIDs = IsNodeExisting(connectionInnovationNumber); foreach (int existingID in existingNodeIDs) { //If the node Id list does not contain one of the existing nodes, break the loop if (!nodeIDs.Contains(existingID)) { return(existingID); } } //If the id is new, add an entry in the log int newID = nodeMutationCounter.GetNewNumber(); AddNodeMutation(connectionInnovationNumber, newID); return(newID); }
public void GetNodeID_Test() { GeneCounter nodeCounter = new GeneCounter(10); List <int> nodesInGenome = new List <int>(); //Get an existing node int result = mutationLog.GetNodeID(connection1.InnovationNumber, nodesInGenome, nodeCounter); Assert.AreEqual(node1.ID, result); //Get a new node number nodesInGenome.Add(result); int result2 = mutationLog.GetNodeID(connection1.InnovationNumber, nodesInGenome, nodeCounter); Assert.AreEqual(10, result2); Assert.AreEqual(2, mutationLog.NodeMutations[connection1.InnovationNumber].Count); //Get the second node again int result3 = mutationLog.GetNodeID(connection1.InnovationNumber, nodesInGenome, nodeCounter); Assert.AreEqual(10, result3); Assert.AreEqual(2, mutationLog.NodeMutations[connection1.InnovationNumber].Count); }
/// <summary> /// Mutate the given agent with different probabilities /// </summary> /// <param name="agent">The agent that should be mutated</param> /// <param name="addConnectionMutationChance">chance to add a connection. Should be between 0f and 1f</param> /// <param name="addNodeMutationChance">chance to add a node. Should be between 0f and 1f</param> /// <param name="mutationWeightChance">chance to mutate the weights. Should be between 0f and 1f</param> /// <param name="nodeInnovationCounter">a node innovation counter</param> /// <param name="connectionInnovationCounter">a connection innovation counter</param> public void MutateAgent(AgentObject agent, float addConnectionMutationChance, float addNodeMutationChance, float mutationWeightChance, GeneCounter nodeInnovationCounter, GeneCounter connectionInnovationCounter, MutationLog mutationLog) { //Mutate weights if (Random.Range(0f, 1f) <= mutationWeightChance) { agent.Genome.MutateConnectionWeight(); } //Mutate Node if (Random.Range(0f, 1f) <= addNodeMutationChance) { AddNodeMutation(agent, _AMOUNT_MUTATION_TRIES, mutationLog, connectionInnovationCounter, nodeInnovationCounter); } //Mutate Connection if (Random.Range(0f, 1f) <= addConnectionMutationChance) { AddConnectionMutation(agent, _AMOUNT_MUTATION_TRIES, mutationLog, connectionInnovationCounter); } }
public void SetUp() { populationManager = new PopulationManager { Callback = this }; //----------------------------------------------------------------------------------- // Parent 1 //----------------------------------------------------------------------------------- parent1Genome = new Genome(); //Create the input nodes parent1Genome.AddNodeGene(new NodeGene(1, NodeGeneType.INPUT, 0f)); parent1Genome.AddNodeGene(new NodeGene(2, NodeGeneType.INPUT, 0f)); parent1Genome.AddNodeGene(new NodeGene(3, NodeGeneType.INPUT, 0f)); //Create the output node parent1Genome.AddNodeGene(new NodeGene(4, NodeGeneType.OUTPUT, 1f)); //Create hidden node parent1Genome.AddNodeGene(new NodeGene(5, NodeGeneType.HIDDEN, 0.5f)); //Create connections parent1Genome.AddConnectionGene(new ConnectionGene(1, 4, 1.0, true, 1)); parent1Genome.AddConnectionGene(new ConnectionGene(2, 4, 1.0, false, 2)); parent1Genome.AddConnectionGene(new ConnectionGene(3, 4, 1.0, true, 3)); parent1Genome.AddConnectionGene(new ConnectionGene(2, 5, 1.0, true, 4)); parent1Genome.AddConnectionGene(new ConnectionGene(5, 4, 1.0, true, 5)); parent1Genome.AddConnectionGene(new ConnectionGene(1, 5, 1.0, true, 8)); //----------------------------------------------------------------------------------- // Parent 2 //----------------------------------------------------------------------------------- parent2Genome = new Genome(); //Create the input nodes parent2Genome.AddNodeGene(new NodeGene(1, NodeGeneType.INPUT, 0f)); parent2Genome.AddNodeGene(new NodeGene(2, NodeGeneType.INPUT, 0f)); parent2Genome.AddNodeGene(new NodeGene(3, NodeGeneType.INPUT, 0f)); //Create the output node parent2Genome.AddNodeGene(new NodeGene(4, NodeGeneType.OUTPUT, 1f)); //Create hidden node parent2Genome.AddNodeGene(new NodeGene(5, NodeGeneType.HIDDEN, 0.4f)); parent2Genome.AddNodeGene(new NodeGene(6, NodeGeneType.HIDDEN, 0.5f)); //Create connections parent2Genome.AddConnectionGene(new ConnectionGene(1, 4, 1.0, true, 1)); parent2Genome.AddConnectionGene(new ConnectionGene(2, 4, 1.0, false, 2)); parent2Genome.AddConnectionGene(new ConnectionGene(3, 4, 1.0, true, 3)); parent2Genome.AddConnectionGene(new ConnectionGene(2, 5, 1.0, true, 4)); parent2Genome.AddConnectionGene(new ConnectionGene(5, 4, 1.0, false, 5)); parent2Genome.AddConnectionGene(new ConnectionGene(5, 6, 1.0, true, 6)); parent2Genome.AddConnectionGene(new ConnectionGene(6, 4, 1.0, true, 7)); parent2Genome.AddConnectionGene(new ConnectionGene(3, 5, 1.0, true, 9)); parent2Genome.AddConnectionGene(new ConnectionGene(1, 6, 1.0, true, 10)); //----------------------------------------------------------------------------------- // Parent 3 //----------------------------------------------------------------------------------- parent3GenomeSimple = new Genome(); //Create the input nodes parent3GenomeSimple.AddNodeGene(new NodeGene(7, NodeGeneType.INPUT, 0f)); parent3GenomeSimple.AddNodeGene(new NodeGene(8, NodeGeneType.INPUT, 0f)); parent3GenomeSimple.AddNodeGene(new NodeGene(9, NodeGeneType.INPUT, 0f)); //Create the output node parent3GenomeSimple.AddNodeGene(new NodeGene(10, NodeGeneType.OUTPUT, 1f)); //Create connections parent3GenomeSimple.AddConnectionGene(new ConnectionGene(7, 10, 1.0, true, 11)); parent3GenomeSimple.AddConnectionGene(new ConnectionGene(8, 10, 1.0, true, 12)); parent3GenomeSimple.AddConnectionGene(new ConnectionGene(9, 10, 1.0, true, 13)); //Init the connection gene counter with 11 connectionInnovationCounter = new GeneCounter(14); nodeInnovationCounter = new GeneCounter(11); //Set result values from callback to null resultAgentsInitalizedAgentList = null; resultAgentsInitializedSpeciesList = null; resultAgentKilled = null; resultAllAgentsKilled = false; //Set fine tuning parameters PopulationManager._FACTOR_EXCESS_GENES = 1; PopulationManager._FACTOR_DISJOINT_GENES = 1; PopulationManager._FACTOR_AVG_WEIGHT_DIF = 0.4f; PopulationManager._THRESHOLD_NUMBER_OF_GENES = 20; PopulationManager._COMPABILITY_THRESHOLD = 3; }
public void AddNodeMutation(AgentObject agent, int amountTries, MutationLog mutationLog, GeneCounter connectionInnovationCounter, GeneCounter nodeCounter) { List <int> connectionKeys = agent.Genome.Connections.Keys.OrderBy(x => x).ToList(); if (connectionKeys.Count <= 0) { return; } for (int i = 0; i < amountTries; i++) { ConnectionGene connection = null; //Check the size of the genome, if the genome is small, take an older gene if (agent.Genome.Nodes.Keys.Count <= _SIZE_THRESHOLD) { connection = agent.Genome.Connections[connectionKeys[Random.Range(0, Mathf.RoundToInt(connectionKeys.Count - (Mathf.Sqrt(connectionKeys.Count))))]]; } else { //Select random connection connection = agent.Genome.Connections[connectionKeys[Random.Range(0, connectionKeys.Count)]]; } //If mutation is possible, mutate the agent if (agent.Genome.IsNodePossible(connection)) { //int nodeID = mutationLog.GetNodeID(connection.InnovationNumber, nodeCounter); int nodeID = mutationLog.GetNodeID(connection.InnovationNumber, agent.Genome.Nodes.Keys.ToList(), nodeCounter); int innovationNumberInToNewNode = mutationLog.GetConnectionInnovationNumber(connection.InNode, nodeID, connectionInnovationCounter); int innovationNumberNewNodeToOut = mutationLog.GetConnectionInnovationNumber(nodeID, connection.OutNode, connectionInnovationCounter); agent.Genome.AddNodeMutation(connection, nodeID, innovationNumberInToNewNode, innovationNumberNewNodeToOut); break; } } }
public void AddConnectionMutation(AgentObject agent, int amountTries, MutationLog mutationLog, GeneCounter connectionInnovationCounter) { List <int> nodeKeys = agent.Genome.Nodes.Keys.ToList(); for (int i = 0; i < amountTries; i++) { //Selet two random nodes NodeGene inNode = agent.Genome.Nodes[nodeKeys[Random.Range(0, nodeKeys.Count)]]; NodeGene outNode = agent.Genome.Nodes[nodeKeys[Random.Range(0, nodeKeys.Count)]]; //If mutation is possible, mutate the agent if (agent.Genome.IsConnectionPossible(inNode, outNode)) { int innovationNumber = mutationLog.GetConnectionInnovationNumber(inNode.ID, outNode.ID, connectionInnovationCounter); agent.Genome.AddConnectionMutation(inNode, outNode, innovationNumber); break; } } }