/// <summary> /// Breed /// </summary> private void Breed() { // Logs Setup int weightMutationNb = 0; int addConnectionNb = 0; int addNodeNb = 0; int enableDisableConnectionNb = 0; _mutationLogs = ""; while (_nextEvaluationGenomes.Count() < _config.populationSize) { Genome child = null; Genome mom = null; Genome dad = null; // Get Child Species species = null; int maxToKeep = ((_config.populationSize * _config.percentageToKeep) / 100) - 1; if (_config.species) { species = GetRandomSpecies(_r); } if (_config.crossover) { if (species != null) { mom = GetRandomGenome(species, _r); dad = GetRandomGenome(species, _r); } else { mom = _genomes[UnityEngine.Random.Range(0, maxToKeep)]; dad = _genomes[UnityEngine.Random.Range(0, maxToKeep)]; } // Crossover between Mom & Dad child = mom.Fitness >= dad.Fitness ? Genome.Crossover(mom, dad, _r, _config.disabledConnectionInheritChance) : Genome.Crossover(dad, mom, _r, _config.disabledConnectionInheritChance); } else { child = species != null ? new Genome(GetRandomGenome(species, _r)) : new Genome(_genomes[UnityEngine.Random.Range(0, maxToKeep)]); } // Weights Mutation if ((float)_r.NextDouble() < _config.mutationRate) { child.WeightsMutation(_r); weightMutationNb++; } if (_config.genomeMutations) { // Add Connection Mutation if ((float)_r.NextDouble() < _config.addConnectionRate) { // If for Logs if (child.AddConnectionMutation(_r, _connectionInnovation, 10)) { addConnectionNb++; } } // Add Node Mutation if ((float)_r.NextDouble() < _config.addNodeRate) { child.AddNodeMutation(_r, _connectionInnovation, _nodeInnovation); addNodeNb++; } // Enable/Disable a Random Connection if ((float)_r.NextDouble() < _config.enableDisableRate) { // If for Logs if (child.EnableOrDisableRandomConnection()) { enableDisableConnectionNb++; } } } // Add Child to Next Evaluation Genomes _nextEvaluationGenomes.Add(child); } _mutationLogs += string.Format( "Weights Mutation: {0}, Add Connection: {1}, Add Node: {2}, Enable/Disable Connection: {3}\nCrossover is {4}, Genome Mutations is {5}, Species is {6}", weightMutationNb, addConnectionNb, addNodeNb, enableDisableConnectionNb, _config.crossover, _config.genomeMutations, _config.species ); _genomes.Clear(); _genomes = new List <Genome>(_nextEvaluationGenomes); _nextEvaluationGenomes = new List <Genome>(); }
// Runs one generation public void Evaluate() { // Reset everything for next generation foreach (Species s in species) { s.Reset(random); } fitnessMap.Clear(); speciesMap.Clear(); nextGenGenomes.Clear(); highestFitness = float.MinValue; fittestGenome = null; // Place genomes into species foreach (Genome g in genomes) { bool foundSpecies = false; foreach (Species s in species) { if (Genome.CompatibilityDistance(g, s.mascot, C1, C2, C3) < DT) { // compatibility distance is less than DT, so genome belongs to this species s.members.Add(g); speciesMap[g] = s; foundSpecies = true; break; } } if (!foundSpecies) { // if there is no appropiate species for genome, make a new one Species newSpecies = new Species(g); species.Add(newSpecies); speciesMap[g] = newSpecies; } } // Remove unused species foreach (Species s in species) { if (!s.members.Any()) { species.Remove(s); } } // Evaluate genomes and assign score foreach (Genome g in genomes) { Species s = speciesMap[g]; // Get species of the genome float score = evaluateGenome(g); // fitness of Genome float adjustedScore = score / speciesMap[g].members.Count; s.AddAdjustedFitness(adjustedScore); s.fitnessPop.Add(new FitnessGenome(g, adjustedScore)); fitnessMap[g] = adjustedScore; if (score > highestFitness) { highestFitness = score; fittestGenome = g; } } // put best genome from each species into next generation // species = species.OrderByDescending(s => s.fitnessPop).ToList(); foreach (Species s in species) { FitnessGenome fittestInSpecies = s.fitnessPop.Max(); nextGenGenomes.Add(fittestInSpecies.genome); } // Breed the rest of the genomes while (nextGenGenomes.Count < populationSize) { // replace removed genomes by randomly breeding Species s = getRandomSpeciesBiasedAjdustedFitness(random); Genome p1 = getRandomGenomeBiasedAdjustedFitness(s, random); Genome p2 = getRandomGenomeBiasedAdjustedFitness(s, random); Genome child = new Genome(); if (fitnessMap[p1] >= fitnessMap[p2]) { child.Crossover(p1, p2); } else { child.Crossover(p2, p1); } if (Random.Range(0f, 1f) < MUTATION_RATE) { child.Mutation(); } if (Random.Range(0f, 1f) < ADD_CONNECTION_RATE) { //Debug.Log("Adding connection mutation..."); child.AddConnectionMutation(connectionInnovation, 10); } if (Random.Range(0f, 1f) < ADD_NODE_RATE) { //Debug.Log("Adding node mutation..."); child.AddNodeMutation(connectionInnovation, nodeInnovation); } nextGenGenomes.Add(child); } genomes = nextGenGenomes; nextGenGenomes = new List <Genome>(); }
/// <summary> /// Breed /// </summary> private Genome Breed(Genome mom = null, Genome dad = null) { Genome child = null; // Get Child if (dad != null && mom != null) { // Crossover between Mom & Dad if (mom.Fitness >= dad.Fitness) { child = Genome.Crossover(mom, dad, _r, _config.disabledConnectionInheritChance); } else { child = Genome.Crossover(dad, mom, _r, _config.disabledConnectionInheritChance); } } else { int maxToKeep = ((_currentPop * _config.percentageToKeep) / 100) - 1; mom = _genomes[UnityEngine.Random.Range(0, maxToKeep)]; dad = _genomes[UnityEngine.Random.Range(0, maxToKeep)]; // Crossover between Mom & Dad if (mom.Fitness >= dad.Fitness) { child = Genome.Crossover(mom, dad, _r, _config.disabledConnectionInheritChance); } else { child = Genome.Crossover(dad, mom, _r, _config.disabledConnectionInheritChance); } } // Weights Mutation if ((float)_r.NextDouble() < _config.mutationRate) { child.WeightsMutation(_r); } if (_config.genomeMutations) { // Add Connection Mutation if ((float)_r.NextDouble() < _config.addConnectionRate) { child.AddConnectionMutation(_r, _connectionInnovation, 10); } // Add Node Mutation if ((float)_r.NextDouble() < _config.addNodeRate) { child.AddNodeMutation(_r, _connectionInnovation, _nodeInnovation); } // Enable/Disable a Random Connection if ((float)_r.NextDouble() < _config.enableDisableRate) { child.EnableOrDisableRandomConnection(); } } return(child); }