Esempio n. 1
0
        /// <summary>
        /// Returns tuple containing 1) percentage of weight values that differ, and 2) the absolute difference in weight values of dna2 as a percentage of the aggregated absolute weight values of dna1
        /// </summary>
        public static System.Tuple <float, double> CompareWeights(Dna dna1, Dna dna2)
        {
            if (!Dna.TopologiesEqual(dna1, dna2))
            {
                throw new System.ArgumentException("Can't compare dna weights of different topologies!");
            }

            if (dna1.WeightsAndBiases.Count != dna2.WeightsAndBiases.Count) // should always be false if topologies are the same. but just in case...
            {
                throw new System.ArgumentException("Weights arrays not equal???");
            }

            double accumulatedAbsoluteDifference = 0;
            int    nWeightsDiffering             = 0;

            for (int i = 0; i < dna1.WeightsAndBiases.Count; i++)
            {
                double absoluteDifference = System.Math.Abs(dna1.WeightsAndBiases[i] - dna2.WeightsAndBiases[i]);
                accumulatedAbsoluteDifference += absoluteDifference;
                if (absoluteDifference > 0)
                {
                    nWeightsDiffering++;
                }
            }

            double dna1TotalWeight = dna1.WeightsAndBiases.Aggregate(0.0, (total, weight) => total + System.Math.Abs(weight));
            double weightDifferenceAsProportion = accumulatedAbsoluteDifference / dna1TotalWeight;

            return(new System.Tuple <float, double>((float)nWeightsDiffering / (float)dna1.WeightsAndBiases.Count, weightDifferenceAsProportion));
        }
Esempio n. 2
0
        public static void DebugDnaDiff(Dna dna1, Dna dna2, string relation)
        {
            var    comparison = CompareWeights(dna1, dna2);
            string log        = System.String.Format("{0} | {1:P2} of weights are different, {2:P2} absolute value difference", relation, comparison.Item1, comparison.Item2);

            Debug.Log(log);
        }
Esempio n. 3
0
        public void AddDna(Dna newDna, bool enforceDistinctive)
        {
            Dna addition = enforceDistinctive && GenePool.Any(dna => dna.Equals(newDna)) ?
                           Dna.CloneAndMutate(newDna, newDna.Heritage, species.MutationSeverity, species.ActivationMutationSeverity) :
                           newDna;

            GenePool.Add(addition);
            Composition.TryGetValue(addition.Heritage, out int count);
            Composition[addition.Heritage] = count + 1;
        }
Esempio n. 4
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());
 }
Esempio n. 5
0
        public static Dna SelectRandomBasedOnFitness(List <Dna> parentPool, Dna excluding = null)
        {
            List <Dna> candidates   = excluding == null ? parentPool : parentPool.Where(p => p != excluding).ToList();
            float      totalFitness = candidates.Aggregate(0f, (total, candidate) => total + candidate.RawFitnessRating); // TODO: optimise this
            List <KeyValuePair <Dna, float> > candidateChances = candidates.ConvertAll(c => new KeyValuePair <Dna, float>(c, c.RawFitnessRating / totalFitness));

            float diceRoll   = Random.Range(0f, 1f);
            float cumulative = 0f;

            for (int i = 0; i < candidateChances.Count; i++)
            {
                cumulative += candidateChances[i].Value;
                if (diceRoll < cumulative)
                {
                    return(candidateChances[i].Key);
                }
            }

            Debug.LogWarning("Failed to choose new random parent by fitness...");
            return(candidates[Random.Range(0, candidates.Count)]);
        }
Esempio n. 6
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);
        }
Esempio n. 7
0
 public Identicle(Dna dna, List <Dna> clonesInPrevGen)
 {
     NextGenDna      = dna;
     ClonesInPrevGen = clonesInPrevGen;
 }