public void EasyGaTest() { MultipointCrossover<ListGenotype<BitGene>, BitGene, double> crossover = new MultipointCrossover<ListGenotype<BitGene>, BitGene, double>(1); EasyGa<ListGenotype<BitGene>, double> algorithm = new EasyGa<ListGenotype<BitGene>, double>.Builder() .WithElitismPercentage(0.5) .WithFitnessFunction(g => g.Count(b => b.Value)) .WithStopCriteria( StopCriteriaBuilder.StopAtGeneration<ListGenotype<BitGene>, double>(2500) .Or(StopCriteriaBuilder.StopAtFitness<ListGenotype<BitGene>, double>(20))) .RegisterBreeder(new BitBreeder(20, 20)) .Register(new RouletteWheelSelector<ListGenotype<BitGene>>(20)) .Register(new Recombinator<ListGenotype<BitGene>, double>(crossover, 2, 10, Recombinator<ListGenotype<BitGene>, double>.RecombinatioNumberType.Absolute)) .Register(new BitBaseMutator<ListGenotype<BitGene>, double>(0.05)) .Build(); Engine<ListGenotype<BitGene>, double> engine = new Engine<ListGenotype<BitGene>, double>.Builder() .WithAlgorithm(algorithm) .Build(); while (!engine.HasReachedStopCriteria) { //if (engine.World != null) //{ // TestContext.WriteLine($"Generation {engine.World.Generation} (Size: {engine.World.Population.Count})"); // foreach (Individual<ListGenotype<BitGene>, double> individual in engine.World.Population) // { // TestContext.WriteLine(individual); // } //} engine.NextGeneration(); } TestContext.WriteLine($"{engine.CurrentWorld.Generation} generations reached"); TestContext.WriteLine($"{engine.Statistics.BestIndividualGeneration} is best indivual's generation"); TestContext.WriteLine($"{engine.Statistics.BestFitness} is best Fitness"); TestContext.WriteLine($"{engine.Statistics.BestGenotype} is best Genotype"); }
public void TestMultipointCrossover() { RandomGenerator rnd = RandomGenerator.GetInstance(); ListGenotype<FloatGene> genotype = new ListGenotype<FloatGene>(new[] {new FloatGene(1), new FloatGene(2), new FloatGene(3), new FloatGene(4), new FloatGene(5)}); ListGenotype<FloatGene> genotype2 = new ListGenotype<FloatGene>(new[] {new FloatGene(1.5), new FloatGene(2.5), new FloatGene(3.5), new FloatGene(4.5), new FloatGene(5.5)}); MultipointCrossover<ListGenotype<FloatGene>, FloatGene, int> crossover = new MultipointCrossover<ListGenotype<FloatGene>, FloatGene, int>(3); List<Individual<ListGenotype<FloatGene>, int>> offspring = crossover.Apply( Individual<ListGenotype<FloatGene>, int>.FromGenotypes(new List<ListGenotype<FloatGene>> { genotype, genotype2 })).ToList(); Assert.AreEqual(offspring.Count, 2); foreach (Individual<ListGenotype<FloatGene>, int> child in offspring) { bool previousWasInteger = Math.Abs(child.Genotype[0].Value - (int) child.Genotype[0].Value) < double.Epsilon; int cuts = 0; foreach (FloatGene gene in child.Genotype) { bool currentIsInteger = Math.Abs(gene.Value - (int) gene.Value) < double.Epsilon; if (currentIsInteger != previousWasInteger) cuts++; previousWasInteger = currentIsInteger; } Assert.AreEqual(3, cuts); } }
public void TestMultipointCrossover() { var innovationIdsA = new int[]{1, 2, 3, 4, 5, 8}; var neuronGenesA = innovationIdsA.Select(i => new NeuronGene(i, NeuronType.HiddenNeuron)).ToGeneList(); var innovationIdsB = new int[]{1, 2, 3, 4, 5, 6, 7, 9, 10}; var neuronGenesB = innovationIdsB.Select(i => new NeuronGene(i, NeuronType.HiddenNeuron)).ToGeneList(); var expectedInnovationIds = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; var genotypeA = new Genotype(neuronGenesA, new GeneList<SynapseGene>(0)); var genotypeB = new Genotype(neuronGenesB, new GeneList<SynapseGene>(0)); var phenotypeA = new Phenotype(genotypeA); var phenotypeB = new Phenotype(genotypeB); var crossover = new MultipointCrossover(); var offspring = crossover.Crossover(phenotypeA, phenotypeB); var offspringInnovationIds = offspring.NeuronGenes.Select(g => g.InnovationId).ToArray(); Assert.AreEqual(expectedInnovationIds, offspringInnovationIds); }
IEnumerator Start() { var logPath = string.Format("logs_{0}", DateTime.Now.Ticks); Debug.LogFormat("Logging to {0}", logPath); if (!Directory.Exists(logPath)) { Directory.CreateDirectory(logPath); } elitesLog = File.CreateText(Path.Combine(logPath, "elites.csv")); populationLog = File.CreateText(Path.Combine(logPath, "populations.csv")); generationLog = File.CreateText(Path.Combine(logPath, "generations.csv")); speciesLog = File.CreateText(Path.Combine(logPath, "species.csv")); var populationSize = 100; var innovations = new InnovationCollection(); var mutations = new MutationCollection(); mutations.Add(0.01f, new AddNeuronMutator(innovations)); // 0.1% mutations.Add(0.05f, new AddSynapseMutator(innovations)); // 1% mutations.Add(0.05f, new ToggleSynapseMutator(0.125f)); mutations.Add(0.20f, new PerturbNeuronMutator(0.5f, 0.25f)); // 98% vvv mutations.Add(0.20f, new PerturbSynapseMutator(0.5f, 0.25f)); mutations.Add(0.20f, new ReplaceNeuronMutator(0.5f)); mutations.Add(0.20f, new ReplaceSynapseMutator(0.5f)); var eliteSelector = new EliteSelector(); var crossover = new MultipointCrossover(); var offspringSelector = new OffspringSelector(crossover); var distanceMetric = new DistanceMetric(2.0f, 2.0f, 1.0f); var speciation = new Speciation(10, 6.0f, 0.3f, distanceMetric); var neuronGenes = new []{ new NeuronGene(innovations.GetInitialNeuronInnovationId(0), NeuronType.UpperNeuron), new NeuronGene(innovations.GetInitialNeuronInnovationId(1), NeuronType.LowerNeuron), new NeuronGene(innovations.GetInitialNeuronInnovationId(2), NeuronType.PositionNeuron), new NeuronGene(innovations.GetInitialNeuronInnovationId(3), NeuronType.SpeedNeuron), }.ToGeneList(); var synapseGenes = new GeneList<SynapseGene>(); var protoGenotype = new Genotype(neuronGenes, synapseGenes); var genotypes = new GenotypeStream(protoGenotype) .Take(populationSize).ToArray(); var species = new Specie[0]; var generation = 0; var elitePhenotypes = new List<Phenotype>(); var offspringPhenotypes = genotypes.Select(gt => new Phenotype(gt)).ToList(); while (true) { yield return StartCoroutine(EvaluatePopulation(offspringPhenotypes)); var phenotypes = new List<Phenotype>(elitePhenotypes.Count + offspringPhenotypes.Count); phenotypes.AddRange(elitePhenotypes); phenotypes.AddRange(offspringPhenotypes); Assert.AreEqual(phenotypes.Count, populationSize, "Population size must remain constant"); var longest = phenotypes.OrderByDescending(pt => pt.BestDuration).First(); Debug.LogFormat("[{0}] Fitness: {1}, Duration: {2}s ({3}, {4}) (Longest)", generation, longest.MeanFitness, longest.MeanDuration, longest.Genotype.NeuronCount, longest.Genotype.SynapseCount); var best = phenotypes.OrderByDescending(pt => pt.Fitness).First(); Debug.LogFormat("[{0}] Fitness: {1}, Duration: {2}s ({3}, {4}) (Best)", generation, best.MeanFitness, best.MeanDuration, best.Genotype.NeuronCount, best.Genotype.SynapseCount); elitesLog.WriteLine(string.Join(",", new string[]{ generation.ToString(), best.Fitness.ToString(), best.BestDuration.ToString(), JSON.Serialize(best.Genotype.ToJSON()), })); var meanComplexity = phenotypes.Aggregate(0.0f, (sum, pt) => sum + (float)pt.Genotype.Complexity, (sum) => sum / (float)phenotypes.Count); var meanNeuronCount = phenotypes.Aggregate(0.0f, (sum, pt) => sum + (float)pt.Genotype.NeuronCount, (sum) => sum / (float)phenotypes.Count); var meanSynapseCount = phenotypes.Aggregate(0.0f, (sum, pt) => sum + (float)pt.Genotype.SynapseCount, (sum) => sum / (float)phenotypes.Count); var meanFitness = phenotypes.Aggregate(0.0f, (sum, pt) => sum + (float)pt.Fitness, (sum) => sum / (float)phenotypes.Count); var stdevFitness = phenotypes.Aggregate(0.0f, (sum, pt) => sum + Mathf.Pow(pt.Fitness - meanFitness, 2.0f), (sum) => Mathf.Sqrt(sum / (float)phenotypes.Count)); var stdevComplexity = phenotypes.Aggregate(0.0f, (sum, pt) => sum + Mathf.Pow((float)pt.Genotype.Complexity - meanComplexity, 2.0f), (sum) => Mathf.Sqrt(sum / (float)phenotypes.Count)); var stdevNeuronCount = phenotypes.Aggregate(0.0f, (sum, pt) => sum + Mathf.Pow((float)pt.Genotype.NeuronCount - meanNeuronCount, 2.0f), (sum) => Mathf.Sqrt(sum / (float)phenotypes.Count)); var stdevSynapseCount = phenotypes.Aggregate(0.0f, (sum, pt) => sum + Mathf.Pow((float)pt.Genotype.SynapseCount - meanSynapseCount, 2.0f), (sum) => Mathf.Sqrt(sum / (float)phenotypes.Count)); species = speciation.Speciate(species, phenotypes.ToArray()); Debug.LogFormat("[{0}] Species Count: {1} (Threshold: {2})", generation, species.Length, speciation.DistanceThreshold); var meanAdjustedFitness = phenotypes.Aggregate(0.0f, (sum, pt) => sum + (float)pt.AdjustedFitness, (sum) => sum / (float)phenotypes.Count); // standard deviation: // take the square root of the average of the squared deviations of the values from their average value var stdevAdjustedFitness = phenotypes.Aggregate(0.0f, (sum, pt) => sum + Mathf.Pow(pt.AdjustedFitness - meanAdjustedFitness, 2.0f), (sum) => Mathf.Sqrt(sum / (float)phenotypes.Count)); generationLog.WriteLine(new []{ generation, best.Fitness, best.MeanDuration, meanAdjustedFitness, stdevAdjustedFitness, meanFitness, stdevFitness, meanComplexity, stdevComplexity, meanNeuronCount, stdevNeuronCount, meanSynapseCount, stdevSynapseCount }.Stringify()); foreach (var sp in species) { speciesLog.WriteLine(new []{ generation, sp.SpeciesId, sp.Count, sp.BestFitness, sp.MeanFitness, sp.MeanAdjustedFitness, sp.MeanComplexity, }.Stringify()); foreach (var pt in sp) { populationLog.WriteLine(new []{ generation, sp.SpeciesId, pt.Fitness, pt.AdjustedFitness, pt.BestDuration, pt.Genotype.Complexity, pt.Genotype.NeuronCount, pt.Genotype.SynapseCount, }.Stringify()); } } var eliteCount = species.Length; elitePhenotypes = eliteSelector.Select(species, eliteCount); var offspringCount = populationSize - elitePhenotypes.Count; var offspringGenotypes = offspringSelector.Select(species, offspringCount); var mutationResults = mutations.Mutate(offspringGenotypes); Debug.LogFormat("[{0}] Mutations: Added Neurons: {1}, Added Synapses: {2}, Perturbed Neurons: {3}, Perturbed Synapses: {4}, Replaced Neurons: {5}, Replaced Synapses: {6}, Toggled Synapses: {7}, Pruned Synapses: {8}, Orphaned Neurons: {9}", generation, mutationResults.addedNeurons, mutationResults.addedSynapses, mutationResults.perturbedNeurons, mutationResults.perturbedSynapses, mutationResults.replacedNeurons, mutationResults.replacedSynapses, mutationResults.toggledSynapses, mutationResults.prunedSynapses, mutationResults.orphanedNeurons); offspringPhenotypes = offspringGenotypes.Select(gt => new Phenotype(gt)).ToList(); generation++; // Flush these so we can preview results while it runs generationLog.Flush(); populationLog.Flush(); speciesLog.Flush(); } }
IEnumerator Start() { var logPath = string.Format("logs_{0}", DateTime.Now.Ticks); Debug.LogFormat("Logging to {0}", logPath); if (!Directory.Exists(logPath)) { Directory.CreateDirectory(logPath); } elitesLog = File.CreateText(Path.Combine(logPath, "elites.csv")); populationLog = File.CreateText(Path.Combine(logPath, "populations.csv")); generationLog = File.CreateText(Path.Combine(logPath, "generations.csv")); speciesLog = File.CreateText(Path.Combine(logPath, "species.csv")); var populationSize = 100; var innovations = new InnovationCollection(); var mutations = new MutationCollection(); mutations.Add(0.01f, new AddNeuronMutator(innovations)); // 0.1% mutations.Add(0.05f, new AddSynapseMutator(innovations)); // 1% mutations.Add(0.05f, new ToggleSynapseMutator(0.125f)); mutations.Add(0.20f, new PerturbNeuronMutator(0.5f, 0.25f)); // 98% vvv mutations.Add(0.20f, new PerturbSynapseMutator(0.5f, 0.25f)); mutations.Add(0.20f, new ReplaceNeuronMutator(0.5f)); mutations.Add(0.20f, new ReplaceSynapseMutator(0.5f)); var eliteSelector = new EliteSelector(); var crossover = new MultipointCrossover(); var offspringSelector = new OffspringSelector(crossover); var distanceMetric = new DistanceMetric(2.0f, 2.0f, 1.0f); var speciation = new Speciation(10, 6.0f, 0.3f, distanceMetric); var neuronGenes = new [] { new NeuronGene(innovations.GetInitialNeuronInnovationId(0), NeuronType.UpperNeuron), new NeuronGene(innovations.GetInitialNeuronInnovationId(1), NeuronType.LowerNeuron), new NeuronGene(innovations.GetInitialNeuronInnovationId(2), NeuronType.PositionNeuron), new NeuronGene(innovations.GetInitialNeuronInnovationId(3), NeuronType.SpeedNeuron), }.ToGeneList(); var synapseGenes = new GeneList <SynapseGene>(); var protoGenotype = new Genotype(neuronGenes, synapseGenes); var genotypes = new GenotypeStream(protoGenotype) .Take(populationSize).ToArray(); var species = new Specie[0]; var generation = 0; var elitePhenotypes = new List <Phenotype>(); var offspringPhenotypes = genotypes.Select(gt => new Phenotype(gt)).ToList(); while (true) { yield return(StartCoroutine(EvaluatePopulation(offspringPhenotypes))); var phenotypes = new List <Phenotype>(elitePhenotypes.Count + offspringPhenotypes.Count); phenotypes.AddRange(elitePhenotypes); phenotypes.AddRange(offspringPhenotypes); Assert.AreEqual(phenotypes.Count, populationSize, "Population size must remain constant"); var longest = phenotypes.OrderByDescending(pt => pt.BestDuration).First(); Debug.LogFormat("[{0}] Fitness: {1}, Duration: {2}s ({3}, {4}) (Longest)", generation, longest.MeanFitness, longest.MeanDuration, longest.Genotype.NeuronCount, longest.Genotype.SynapseCount); var best = phenotypes.OrderByDescending(pt => pt.Fitness).First(); Debug.LogFormat("[{0}] Fitness: {1}, Duration: {2}s ({3}, {4}) (Best)", generation, best.MeanFitness, best.MeanDuration, best.Genotype.NeuronCount, best.Genotype.SynapseCount); elitesLog.WriteLine(string.Join(",", new string[] { generation.ToString(), best.Fitness.ToString(), best.BestDuration.ToString(), JSON.Serialize(best.Genotype.ToJSON()), })); var meanComplexity = phenotypes.Aggregate(0.0f, (sum, pt) => sum + (float)pt.Genotype.Complexity, (sum) => sum / (float)phenotypes.Count); var meanNeuronCount = phenotypes.Aggregate(0.0f, (sum, pt) => sum + (float)pt.Genotype.NeuronCount, (sum) => sum / (float)phenotypes.Count); var meanSynapseCount = phenotypes.Aggregate(0.0f, (sum, pt) => sum + (float)pt.Genotype.SynapseCount, (sum) => sum / (float)phenotypes.Count); var meanFitness = phenotypes.Aggregate(0.0f, (sum, pt) => sum + (float)pt.Fitness, (sum) => sum / (float)phenotypes.Count); var stdevFitness = phenotypes.Aggregate(0.0f, (sum, pt) => sum + Mathf.Pow(pt.Fitness - meanFitness, 2.0f), (sum) => Mathf.Sqrt(sum / (float)phenotypes.Count)); var stdevComplexity = phenotypes.Aggregate(0.0f, (sum, pt) => sum + Mathf.Pow((float)pt.Genotype.Complexity - meanComplexity, 2.0f), (sum) => Mathf.Sqrt(sum / (float)phenotypes.Count)); var stdevNeuronCount = phenotypes.Aggregate(0.0f, (sum, pt) => sum + Mathf.Pow((float)pt.Genotype.NeuronCount - meanNeuronCount, 2.0f), (sum) => Mathf.Sqrt(sum / (float)phenotypes.Count)); var stdevSynapseCount = phenotypes.Aggregate(0.0f, (sum, pt) => sum + Mathf.Pow((float)pt.Genotype.SynapseCount - meanSynapseCount, 2.0f), (sum) => Mathf.Sqrt(sum / (float)phenotypes.Count)); species = speciation.Speciate(species, phenotypes.ToArray()); Debug.LogFormat("[{0}] Species Count: {1} (Threshold: {2})", generation, species.Length, speciation.DistanceThreshold); var meanAdjustedFitness = phenotypes.Aggregate(0.0f, (sum, pt) => sum + (float)pt.AdjustedFitness, (sum) => sum / (float)phenotypes.Count); // standard deviation: // take the square root of the average of the squared deviations of the values from their average value var stdevAdjustedFitness = phenotypes.Aggregate(0.0f, (sum, pt) => sum + Mathf.Pow(pt.AdjustedFitness - meanAdjustedFitness, 2.0f), (sum) => Mathf.Sqrt(sum / (float)phenotypes.Count)); generationLog.WriteLine(new [] { generation, best.Fitness, best.MeanDuration, meanAdjustedFitness, stdevAdjustedFitness, meanFitness, stdevFitness, meanComplexity, stdevComplexity, meanNeuronCount, stdevNeuronCount, meanSynapseCount, stdevSynapseCount }.Stringify()); foreach (var sp in species) { speciesLog.WriteLine(new [] { generation, sp.SpeciesId, sp.Count, sp.BestFitness, sp.MeanFitness, sp.MeanAdjustedFitness, sp.MeanComplexity, }.Stringify()); foreach (var pt in sp) { populationLog.WriteLine(new [] { generation, sp.SpeciesId, pt.Fitness, pt.AdjustedFitness, pt.BestDuration, pt.Genotype.Complexity, pt.Genotype.NeuronCount, pt.Genotype.SynapseCount, }.Stringify()); } } var eliteCount = species.Length; elitePhenotypes = eliteSelector.Select(species, eliteCount); var offspringCount = populationSize - elitePhenotypes.Count; var offspringGenotypes = offspringSelector.Select(species, offspringCount); var mutationResults = mutations.Mutate(offspringGenotypes); Debug.LogFormat("[{0}] Mutations: Added Neurons: {1}, Added Synapses: {2}, Perturbed Neurons: {3}, Perturbed Synapses: {4}, Replaced Neurons: {5}, Replaced Synapses: {6}, Toggled Synapses: {7}, Pruned Synapses: {8}, Orphaned Neurons: {9}", generation, mutationResults.addedNeurons, mutationResults.addedSynapses, mutationResults.perturbedNeurons, mutationResults.perturbedSynapses, mutationResults.replacedNeurons, mutationResults.replacedSynapses, mutationResults.toggledSynapses, mutationResults.prunedSynapses, mutationResults.orphanedNeurons); offspringPhenotypes = offspringGenotypes.Select(gt => new Phenotype(gt)).ToList(); generation++; // Flush these so we can preview results while it runs generationLog.Flush(); populationLog.Flush(); speciesLog.Flush(); } }