/// <summary> /// Toggles the frozen status of a single gene if possible. /// </summary> /// <param name="genome">The genome to be mutated.</param> /// <param name="rando">A random number generator.</param> public static void MutateToggleFreeze(Genome genome, Random rando) { int geneId = rando.Next(genome.Size()); Gene gene = genome.Genes[geneId]; gene.Frozen = !gene.Frozen; if (!genome.Validate(true)) { gene.Frozen = !gene.Frozen; } }
/// <summary> /// Yarr... this be copied almost exactly as the original NEAT. /// In the original NEAT, none of the settings had chance this would happen. /// </summary> /// <param name="style">The specific type of multi-point mating style.</param> /// <param name="mother">A parent genome.</param> /// <param name="father">A parent genome.</param> /// <param name="rando">A random number generator.</param> /// <returns>A product of the given multi-point mating style.</returns> private static Genome MateSinglePoint(MatingStyle style, Genome mother, Genome father, Random rando) { mother.SortGenesByConnectionId(); father.SortGenesByConnectionId(); Genome largerParent = mother; Genome smallerParent = father; if (father.Size() > mother.Size()) { largerParent = father; smallerParent = mother; } List <Gene> childGenes = new List <Gene>(); int largerIndex = 0; int smallerIndex = 0; int crossoverPoint = rando.Next(smallerParent.Size()); int crossoverCounter = 0; while (smallerParent.Size() != smallerIndex) { Gene chosenGene = new Gene(); if (largerIndex == largerParent.Size()) { chosenGene.Copy(smallerParent.Genes[smallerIndex]); smallerIndex++; } else if (smallerIndex == smallerParent.Size()) { //Should never happen chosenGene.Copy(largerParent.Genes[largerIndex]); largerIndex++; } else { int largerGeneId = largerParent.Genes[largerIndex].Id; int smallerGeneId = smallerParent.Genes[smallerIndex].Id; if (largerGeneId == smallerGeneId) { if (crossoverCounter < crossoverPoint) { chosenGene.Copy(largerParent.Genes[largerIndex]); } else if (crossoverCounter > crossoverPoint) { chosenGene.Copy(smallerParent.Genes[smallerIndex]); } else { switch (style) { case MatingStyle.SinglePoint: //Function is equivalent to what is needed here despite the misleading name. MateMultiPointAverage(chosenGene, largerParent.Genes[largerIndex], smallerParent.Genes[smallerIndex], rando); break; default: throw new Exception("MateSinglePoint was not given a valid mating style."); } } chosenGene.Frozen = false; //The NEAT implementation did not call for a chance this would happen. It just did it. [ NEAT.1.2.1 => Genome::mate_singlepoint(...) ] if (largerParent.Genes[largerIndex].Frozen || smallerParent.Genes[smallerIndex].Frozen) { chosenGene.Frozen = true; } largerIndex++; smallerIndex++; crossoverCounter++; } else if (largerGeneId < smallerGeneId) { if (crossoverCounter < crossoverPoint) { chosenGene.Copy(largerParent.Genes[largerIndex]); largerIndex++; crossoverCounter++; } else { chosenGene.Copy(smallerParent.Genes[smallerIndex]); smallerIndex++; } } else { smallerIndex++; continue; } } if (GeneIsUnique(chosenGene, childGenes)) { childGenes.Add(chosenGene); } } return(new Genome(childGenes)); }
/// <summary> /// Classic compatibility function as implemented in the original NEAT. /// </summary> /// <param name="p1">The first genome.</param> /// <param name="p2">The second genome.</param> /// <returns>A measure of how far apart the two Genomes are.</returns> public static double Compatibility(Genome p1, Genome p2) { p1.SortGenesByConnectionId(); p2.SortGenesByConnectionId(); int p1Gene = 0; int p2Gene = 0; int p1End = p1.Size(); int p2End = p2.Size(); int disjointCount = 0; int excessCount = 0; int commonGeneCount = 0; double totalWeightDifferences = 0; while (p1Gene != p1End || p2Gene != p2End) { if (p1Gene == p1End) { p2Gene++; excessCount++; } else if (p2Gene == p2End) { p1Gene++; excessCount++; } else { Gene g1 = p1.Genes[p1Gene]; Gene g2 = p2.Genes[p2Gene]; if (g1.Id == g2.Id) { commonGeneCount++; totalWeightDifferences += Math.Abs(g1.Weight - g2.Weight); p1Gene++; p2Gene++; } else if (g1.Id < g2.Id) { disjointCount++; p1Gene++; } else { disjointCount++; p2Gene++; } } } int N = 1; if (p1End >= GenomeSizeNormalizationThresh || p2End >= GenomeSizeNormalizationThresh) { N = Math.Max(p1End, p2End); } double ret = DisjointCoefficient * disjointCount / N + ExcessCoefficient * excessCount / N + AvgWeightDiffCoefficient * (totalWeightDifferences / commonGeneCount); return(ret); }