public void PerformsDnaMutation() { // Arrange const int nInputs = 2; const int nOutputs = 2; const int outputLayerActivationIndex = 3; int[] hiddenLayers = new int[] { 7 }; Dna originalDna = Dna.GenerateRandomDnaEncoding(nInputs, hiddenLayers, nOutputs, (ActivationType)outputLayerActivationIndex, true); float weightMutationPrevalence = 0.2f; // Act Dna mutatedDna = Dna.CloneAndMutate(originalDna, DnaHeritage.MutatedElite, weightMutationPrevalence, 0.8f); // Assert CheckDnaIsNotReferentiallyEqual(originalDna, mutatedDna); // Structure mutatedDna.OutputsPerLayer.Should().Equal(originalDna.OutputsPerLayer); mutatedDna.Heritage.Should().Be(DnaHeritage.MutatedElite); // Weights mutatedDna.WeightsAndBiases.Should().NotEqual(originalDna.WeightsAndBiases); mutatedDna.WeightsAndBiases.Should().HaveCount(originalDna.WeightsAndBiases.Count); List <double> mutatedWeights = new List <double>(); for (int i = 0; i < originalDna.WeightsAndBiases.Count; i++) { if (originalDna.WeightsAndBiases[i] != mutatedDna.WeightsAndBiases[i]) { mutatedWeights.Add(mutatedDna.WeightsAndBiases[i]); } } mutatedWeights.Should().HaveCount(Mathf.CeilToInt(weightMutationPrevalence * originalDna.WeightsAndBiases.Count)); // Activation mutatedDna.ActivationIndexes.Should().NotEqual(originalDna.ActivationIndexes); mutatedDna.ActivationIndexes.Should().HaveCount(originalDna.ActivationIndexes.Count); int indexOfOutputLayerActivation = originalDna.ActivationIndexes.Count - nOutputs; mutatedDna.ActivationIndexes.Skip(indexOfOutputLayerActivation) .Should().Equal(originalDna.ActivationIndexes.Skip(indexOfOutputLayerActivation), "preserves output layer activation functions"); }