Example #1
0
        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();
        }
    }
Example #5
0
    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();
        }
    }