/// <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)); }
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); }
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; }
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()); }
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)]); }
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); }
public Identicle(Dna dna, List <Dna> clonesInPrevGen) { NextGenDna = dna; ClonesInPrevGen = clonesInPrevGen; }