Пример #1
0
    public void CreateGenerationFromPreviousTest()
    {
        // Arrange
        int[]      hiddenLayers = new int[] { 4, 3, 6 };
        CarSpecies species      = CarSpecies.CreateInstance(typeof(CarSpecies)) as CarSpecies;

        species.GenerationSize = 100;
        species.HeterogeneousHiddenActivation  = false;
        species.HiddenLayersNeuronCount        = hiddenLayers;
        species.ActivationMutationSeverity     = 0f;
        species.ProportionUnchanged            = 0.05f;
        species.ProportionMutatantsOfUnchanged = 0.2f;
        species.OffspringMutationProbability   = 0.5f;
        species.NewDnaRate = 0.05f;

        Generation seed = Generation.CreateSeed(species, 1);

        AssertDnaHeterogeneity(seed.GenePool);

        // Act
        Generation TNG = Generation.FromPrevious(seed, 1);

        // Assert
        AssertOnDerrivedGenerationDna(species, seed.GenePool, TNG.GenePool);
    }
Пример #2
0
    public void CreateSeedGenerationTest()
    {
        // Arrange
        int spawnIndex = 3;

        int[]      hiddenLayers = new int[] { 4, 3, 6 };
        CarSpecies species      = CarSpecies.CreateInstance(typeof(CarSpecies)) as CarSpecies;

        species.HiddenLayersNeuronCount = hiddenLayers;
        int[] expectedOutputsPerLayer = new int[]
        {
            species.Inputs,
            hiddenLayers[0],
            hiddenLayers[1],
            hiddenLayers[2],
            CarSpecies.Outputs,
        };

        // Act
        Generation TNG = Generation.CreateSeed(species, spawnIndex);

        // Assert
        TNG.SpawnLocationIndex.Should().Be(spawnIndex);
        TNG.GenePool.Should().HaveCount(species.GenerationSize);
        TNG.GenePool.Should().OnlyHaveUniqueItems();
        AssertDnaHeterogeneity(TNG.GenePool);
        foreach (Dna dna in TNG.GenePool)
        {
            dna.Heritage.Should().Be(DnaHeritage.New);
            dna.OutputsPerLayer.Should().Equal(expectedOutputsPerLayer);
        }
    }
Пример #3
0
        public static Generation CreateSeed(CarSpecies species, int spawnLocationIndex)
        {
            Generation seed = new Generation(species, 0, spawnLocationIndex);

            seed.AddMultipleDna(GenerateRandomDna(species, species.GenerationSize), false);
            return(seed);
        }
Пример #4
0
 private Generation(CarSpecies species, int generationNumber, int spawnIndex, IEnumerable <Dna> genes = null)
 {
     GenerationNumber   = generationNumber;
     SpawnLocationIndex = spawnIndex;
     GenePool           = new List <Dna>(species.GenerationSize);
     this.species       = species;
 }
Пример #5
0
 private static List <Dna> GenerateRandomDna(CarSpecies species, int number)
 {
     return(Enumerable.Range(0, number).Select((_) =>
                                               Dna.GenerateRandomDnaEncoding(
                                                   species.Inputs,
                                                   species.HiddenLayersNeuronCount,
                                                   CarSpecies.Outputs,
                                                   species.OutputLayerActivation,
                                                   species.HeterogeneousHiddenActivation
                                                   )
                                               ).ToList());
 }
Пример #6
0
    static void AssertOnDerrivedGenerationDna(CarSpecies species, List <Dna> previousGenDna, List <Dna> TNGdna)
    {
        int[] expectedOutputsPerLayer = new int[] { species.Inputs }.Concat(species.HiddenLayersNeuronCount).Append(CarSpecies.Outputs).ToArray();
        int   expectedNumberNew                = Mathf.RoundToInt(species.NewDnaRate * 100);
        int   expectedNumberUnchanged          = Mathf.RoundToInt(species.ProportionUnchanged * 100);
        int   expectedNumberMutantsOfUnchanged = Mathf.RoundToInt(species.ProportionMutatantsOfUnchanged * 100);
        int   sumNewUnchangedMutated           = expectedNumberNew + expectedNumberUnchanged + expectedNumberMutantsOfUnchanged;

        if (sumNewUnchangedMutated % 2 == 1)
        {
            expectedNumberMutantsOfUnchanged++;
        }
        int expectedNumberOffspring        = species.GenerationSize - (expectedNumberNew + expectedNumberUnchanged + expectedNumberMutantsOfUnchanged);
        int expectedNumberMutatedOffspring = Mathf.RoundToInt(expectedNumberOffspring * species.OffspringMutationProbability);

        expectedNumberOffspring.Should().BeGreaterOrEqualTo(expectedNumberMutatedOffspring);

        // Topologies
        foreach (Dna dna in TNGdna)
        {
            dna.OutputsPerLayer.Should().Equal(expectedOutputsPerLayer);
            dna.ActivationIndexes.Should().OnlyContain(i => i == (int)species.OutputLayerActivation);
        }

        // Expected proportions
        TNGdna.Where(d => d.Heritage == DnaHeritage.New).Should().HaveCount(expectedNumberNew);
        TNGdna.Where(d => d.Heritage == DnaHeritage.Elite).Should().HaveCount(expectedNumberUnchanged);
        TNGdna.Where(d => d.Heritage == DnaHeritage.MutatedElite).Should().HaveCount(expectedNumberMutantsOfUnchanged);
        TNGdna.Where(d => d.Heritage == DnaHeritage.MutatedOffspring).Count().Should().BeInRange(
            Mathf.RoundToInt(expectedNumberMutatedOffspring * 0.5f),
            Mathf.RoundToInt(expectedNumberMutatedOffspring * 1.5f)
            );
        TNGdna.Where(d =>
                     d.Heritage != DnaHeritage.New &&
                     d.Heritage != DnaHeritage.Elite &&
                     d.Heritage != DnaHeritage.MutatedElite
                     )
        .Should().HaveCount(expectedNumberOffspring);
        previousGenDna.Concat(TNGdna).Should().OnlyHaveUniqueItems();
        TNGdna.Should().HaveCount(species.GenerationSize);

        // Genetic variation
        AssertDnaHeterogeneity(TNGdna);

        // Genetic variation from previous
        foreach (Dna g2Dna in TNGdna.Where(d => d.Heritage != DnaHeritage.Elite))
        {
            previousGenDna.Any(g1Dna => g1Dna.Equals(g2Dna)).Should().BeFalse();
        }
    }
Пример #7
0
 public void Initialise(CarSpecies carSpecies, Action DieCallback)
 {
     deathCalled = false;
     species     = carSpecies;
     colliderTrigger.TriggerEntered += HandleColliderTriggerEnter;
     callDeath = () =>
     {
         if (deathCalled)
         {
             return;
         }
         deathCalled = true;
         DieCallback();
     };
     initialised = true;
 }
Пример #8
0
    public void CreateGenerationsIterativelyTest()
    {
        // Arrange
        int[]      hiddenLayers = new int[] { 4, 3, 6 };
        CarSpecies species      = CarSpecies.CreateInstance(typeof(CarSpecies)) as CarSpecies;

        species.GenerationSize = 100;
        species.HeterogeneousHiddenActivation  = false;
        species.HiddenLayersNeuronCount        = hiddenLayers;
        species.ActivationMutationSeverity     = 0f;
        species.ProportionUnchanged            = 0.05f;
        species.ProportionMutatantsOfUnchanged = 0.2f;
        species.OffspringMutationProbability   = 0.5f;
        species.NewDnaRate      = 0.05f;
        species.CrossoverPasses = 5;

        Generation seed = Generation.CreateSeed(species, 1);

        AssertDnaHeterogeneity(seed.GenePool);

        Generation previous = seed;

        for (int i = 1; i < 101; i++)
        {
            AssignFakeFitness(previous);

            // Act
            Generation TNG = Generation.FromPrevious(previous, 1);
            Debug.Log("Created gen " + i);

            // Assert
            AssertOnDerrivedGenerationDna(species, previous.GenePool, TNG.GenePool);

            previous = TNG;
        }
    }
Пример #9
0
 public void Initialise(CarSpecies carSpecies)
 {
     species         = carSpecies;
     SensorRotations = species.SensorAngles.Select(angle => Quaternion.AngleAxis(angle, Vector3.up)).ToList();
 }
Пример #10
0
        public static Generation FromPrevious(Generation previous, int spawnLocationIndex)
        {
            CarSpecies species          = previous.species;
            List <Dna> previousGenePool = previous.GenePool;
            Generation TNG = new Generation(species, previous.GenerationNumber + 1, spawnLocationIndex);

            // Create and add fresh dna into next gen
            int nNew = Mathf.RoundToInt(species.GenerationSize * species.NewDnaRate);

            if (nNew > 0)
            {
                TNG.AddMultipleDna(GenerateRandomDna(species, nNew), false);
            }

            //  Preserve elites
            var previousGenerationOrderedByFitness = previousGenePool.OrderByDescending((dna => dna.RawFitnessRating));
            int nElites = Mathf.RoundToInt(species.GenerationSize * species.ProportionUnchanged);

            if (nElites > 0)
            {
                TNG.AddMultipleDna(previousGenerationOrderedByFitness.Take(nElites).Select(dna => Dna.Clone(dna)), true);
            }

            // Add mutated versions of elites
            int nMutatedElites = Mathf.RoundToInt(species.GenerationSize * species.ProportionMutatantsOfUnchanged);

            if (((species.GenerationSize - (nElites + nMutatedElites + nNew)) % 2 == 1))
            {
                nMutatedElites++;                                                                          // make sure remaining spaces for offspring is an even number
            }
            for (int i = 0; i < nMutatedElites; i++)
            {
                Dna randomElite = Darwin.SelectRandomBasedOnFitness(
                    previousGenerationOrderedByFitness.Take(Mathf.RoundToInt(species.GenerationSize * 0.2f)).ToList()
                    );
                Dna mutatedElite = Dna.CloneAndMutate(randomElite, DnaHeritage.MutatedElite, species.MutationSeverity, species.ActivationMutationSeverity);
                TNG.AddDna(mutatedElite, true);
            }

            // Populate the rest with offspring of previous
            int nMutatedOffspring         = 0;
            int freeSpacesForOffspring    = species.GenerationSize - (nElites + nMutatedElites + nNew);
            int targetNumMutatedOffspring = Mathf.RoundToInt(freeSpacesForOffspring * species.OffspringMutationProbability);

            for (int i = 0; i < Mathf.RoundToInt(freeSpacesForOffspring / 2); i++)
            {
                Dna        parent1  = Darwin.SelectRandomBasedOnFitness(previousGenePool);
                Dna        parent2  = Darwin.SelectRandomBasedOnFitness(previousGenePool, parent1);
                List <Dna> children = new List <Dna>(2);

                /* Attempts at crossover may fail if the genomes of the 2 parents are too similar. If for example:
                 *  p1 = 1,2,3,4
                 *  p2 = 1,2,3,5
                 * then no matter how we try to cross them, the children will end up as clones of the parents. To mitigate
                 * this we try a few times and if we consistently fail, then we mutate the dna as a fallback
                 */
                bool crossoverFailed = false;
                for (int crossoverAttempt = 0; crossoverAttempt < 5; crossoverAttempt++)
                {
                    children = Dna.CreateOffspring(
                        parent1,
                        parent2,
                        species.CrossoverPasses,
                        species.IncludeActivationCrossover
                        );
                    crossoverFailed = parent1.Equals(children[0]) || parent1.Equals(children[1]) || parent2.Equals(children[0]) || parent2.Equals(children[1]) || children[0].Equals(children[1]);
                    if (!crossoverFailed)
                    {
                        break;
                    }
                }
                if (crossoverFailed)
                {
                    Debug.LogWarning("Crossover failed after several attempts - selected parent genomes are likely too similar. Falling back to mutation");
                }

                if (crossoverFailed || (nMutatedOffspring <= targetNumMutatedOffspring && Random.Range(0f, 1f) < species.OffspringMutationProbability))
                {
                    TNG.AddMultipleDna(children.ConvertAll(c => Dna.CloneAndMutate(c, DnaHeritage.MutatedOffspring, species.MutationSeverity, species.ActivationMutationSeverity)), true);
                    nMutatedOffspring += 2;
                }
                else
                {
                    TNG.AddMultipleDna(children, true);
                }
            }

            DnaUtils.DebugGenerationDiff(previousGenePool, TNG.GenePool);
            return(TNG);
        }