AdjustFitnesses() { float total = 0; for (int i = 0; i < m_vecMembers.Count; i++) { CGenome member = m_vecMembers[i]; float fitness = member.Fitness(); if (m_iAge < _params.YoungAgeThreshold) { fitness *= _params.YoungFitnessBonus; } else if (m_iAge > _params.OldAgeThreshold) { fitness *= _params.OldAgePenalty; } total += fitness; // Calculation of fitness sharing float adjustedFitness = fitness / m_vecMembers.Count; member.SetAdjustedFitness(adjustedFitness); } }
ResetAndKill() { m_dTotFitAdj = 0; m_dAvFitAdj = 0; // Purge the species that doesn't improve for (int i = m_vecSpecies.Count - 1; i >= 0; i--) { CSpecies species = m_vecSpecies[i]; species.Purge(); if (species.GensNoImprovement() > _params.NumGensAllowedNoImprovement && species.BestFitness() < m_dBestEverFitness) { m_vecSpecies.RemoveAt(i); Debug.Log("killed species " + species.ID()); } } for (int i = 0; i < m_Population.Count; i++) { CGenome genome = m_Population[i]; genome.DeletePhenotype(); } }
CalculateSpawnAmount() { for (int i = 0; i < m_vecMembers.Count; i++) { CGenome member = m_vecMembers[i]; m_dAmountToSpawn += member.AmountToSpawn(); } }
CSpecies(CGenome leader, int speciesID) { m_vecMembers = new List <CGenome> (); m_iSpeciesID = speciesID; m_dBestFitness = leader.Fitness(); m_Leader = leader; m_vecMembers.Add(leader); }
Epoch(Dictionary <int, float> fitnessScores) { if (fitnessScores.Count != m_Population.Count) { Debug.LogError("scores and genomes mismatch error. (" + fitnessScores.Count + " / " + m_Population.Count + ")"); return(null); } ResetAndKill(); for (int i = 0; i < m_Population.Count; i++) { CGenome genome = m_Population[i]; genome.SetFitness(fitnessScores[genome.ID()]); } SortAndRecord(); SpeciateGenomes(); CalculateSpawnLevels(); Debug.Log("best fitness last gen: " + m_Population[0].Fitness()); List <CGenome> newPopulation = new List <CGenome> (); int numSpawned = SpawnLeaders(newPopulation); for (int i = 0; i < m_vecSpecies.Count; i++) { CSpecies species = m_vecSpecies[i]; numSpawned = SpawnOffspring(species, numSpawned, newPopulation); } /* * Tournament selection is used over the entire population if due * to a underflow of the species amount to spawn the offspring * doesn't fill the entire population additional children needs to * created. */ if (numSpawned < _params.NumGenomesToSpawn) { int numMoreToSpawn = _params.NumGenomesToSpawn - numSpawned; while (numMoreToSpawn-- > 0) { CGenome baby = new CGenome(TournamentSelection(m_PopSize / 5)); baby.SetID(++nextGenomeID); newPopulation.Add(baby); } } m_Population = newPopulation; m_iGeneration++; return(CreatePhenotypes()); }
SpawnLeaders(List <CGenome> newPopulation) { for (int i = 0; i < m_vecSpecies.Count; i++) { CSpecies species = m_vecSpecies[i]; CGenome baby = species.Leader(); Debug.Log("spawning leader (" + baby.Fitness() + "): " + baby.ID() + " for " + species.ID()); newPopulation.Add(baby); } return(newPopulation.Count); }
CreatePhenotypes() { List <CNeuralNet> newPhenotypes = new List <CNeuralNet> (); for (int i = 0; i < m_Population.Count; i++) { CGenome genome = m_Population[i]; int depth = CalculateNetDepth(genome); newPhenotypes.Add(genome.CreatePhenotype(depth)); } return(newPhenotypes); }
AddMember(CGenome genome) { if (genome.Fitness() > m_dBestFitness) { m_dBestFitness = genome.Fitness(); m_iGensWithoutImproving = 0; m_Leader = genome; } m_vecMembers.Add(genome); /* * m_vecMembers.Sort(delegate (CGenome a, CGenome b) { * return b.Fitness().CompareTo(a.Fitness()); * });*/ }
CGenome(CGenome original) { m_vecLinks = new List <SLinkGene> (); m_vecNeurons = new List <SNeuronGene>(); for (int i = 0; i < original.m_vecLinks.Count; i++) { m_vecLinks.Add(new SLinkGene(original.m_vecLinks[i])); } for (int i = 0; i < original.m_vecNeurons.Count; i++) { m_vecNeurons.Add(new SNeuronGene(original.m_vecNeurons[i])); } m_iNumInputs = original.m_iNumInputs; m_iNumOutputs = original.m_iNumOutputs; m_GenomeID = original.m_GenomeID; }
CalculateNetDepth(CGenome genome) { int maxDepth = 0; for (int i = 0; i < genome.NumNeurons(); i++) { for (int j = 0; j < vecSplits.Count; j++) { SplitDepth split = vecSplits[i]; if (genome.SplitY(i) == split.value && split.depth > maxDepth) { maxDepth = split.depth; } } } return(maxDepth + 2); }
TournamentSelection(int numSelections) { double bestFitness = 0; CGenome best = m_Population[0]; for (int i = 0; i < numSelections; i++) { CGenome genome = m_Population[Random.Range(0, m_Population.Count)]; if (genome.Fitness() > bestFitness) { best = genome; bestFitness = genome.Fitness(); } } return(best); }
DetermineBestParent(CGenome mum, CGenome dad) { if (mum.Fitness() == dad.Fitness()) { if (mum.NumGenes() == dad.NumGenes()) { if (Random.value < 0.5) { return(ParentType.Mum); } else { return(ParentType.Dad); } } else { /* * Choose the parent with the fewest genes because * the fitness is the same. */ if (mum.NumGenes() < dad.NumGenes()) { return(ParentType.Mum); } else { return(ParentType.Dad); } } } else { if (mum.Fitness() > dad.Fitness()) { return(ParentType.Mum); } else { return(ParentType.Dad); } } }
MutateBaby(CGenome baby) { if (baby.NumNeurons() < _params.MaxPermittedNeurons) { baby.AddNeuron(_params.ChanceAddNode, innovation, _params.NumTriesToFindOldLink); } baby.AddLink(_params.ChanceAddLink, _params.ChanceAddRecurrentLink, innovation, _params.NumTriesToFindLoopedLink, _params.NumAddLinkAttempts); baby.MutateWeights(_params.MutationRate, _params.ChanceWeightReplaced, _params.MaxWeightPerturbation); baby.MutateActivationResponse(_params.ActivationMutationRate, _params.MaxActivationPerturbation); }
CalculateSpawnLevels() { for (int i = 0; i < m_Population.Count; i++) { CGenome genome = m_Population[i]; float toSpawn = 0; if (m_dAvFitAdj > 0) { toSpawn = genome.GetAdjustedFitness() / m_dAvFitAdj; } genome.SetAmountToSpawn(toSpawn); } for (int i = 0; i < m_vecSpecies.Count; i++) { CSpecies species = m_vecSpecies[i]; species.CalculateSpawnAmount(); } }
Cga(int inputs, int outputs) { m_Population = new List <CGenome> (); for (int i = 0; i < _params.NumGenomesToSpawn; i++) { m_Population.Add(new CGenome(nextGenomeID++, inputs, outputs)); } m_PopSize = m_Population.Count; // Create simple genome used for innovations database CGenome genome = new CGenome(1, inputs, outputs); m_vecSpecies = new List <CSpecies> (); innovation = new CInnovation(genome.GetLinks(), genome.GetNeurons()); vecSplits = new List <SplitDepth> (); // Create the network depth lookup table. Split(0, 1, 0); }
Crossover(CGenome mum, CGenome dad) { ParentType best = DetermineBestParent(mum, dad); // The resulting offspring produced are stored in these lists. List <SNeuronGene> babyNeurons = new List <SNeuronGene>(); List <SLinkGene> babyGenes = new List <SLinkGene>(); List <int> neuronIDs = new List <int>(); SelectGenesToBreed(mum, dad, best, babyGenes, neuronIDs); neuronIDs.Sort(); // Create the new neurons using the neuron ids. for (int i = 0; i < neuronIDs.Count; i++) { int neuronID = neuronIDs[i]; babyNeurons.Add(this.innovation.CreateNeuronByID(neuronID)); } // Create the baby genome using the newly created neurons. return(new CGenome(nextGenomeID++, babyNeurons, babyGenes, mum.NumInputs(), mum.NumOutputs())); }
GetCompatibilityScore(CGenome other) { /* * Keep track of these numbers because genomes with different * topologies are unlikely to group together well. Therefore * the compatability score is based on how different the * topologies of the genomes are. */ float numDisjointGenes = 0; float numExcessGenes = 0; float numMatchedGenes = 0; /* * The combined error/difference between the weights of the genomes. * A lower score means the behaviour is more probable to be * similar. */ float weightDifference = 0; CalculateTopologyDifference(out numDisjointGenes, out numExcessGenes, out numMatchedGenes, out weightDifference, other); float longest = Mathf.Max(NumGenes(), other.NumGenes()); /* * Coeffecients that are tweaked to influence the score * roughly the same amount. */ const float coefDisjoint = 1.0f; const float coefExcess = 1.0f; const float coefMatched = 0.4f; return((coefExcess * numExcessGenes / longest) + (coefDisjoint * numDisjointGenes / longest) + (coefMatched * weightDifference / numMatchedGenes)); }
SpawnOffspring(CSpecies species, int numSpawned, List <CGenome> newPopulation) { CGenome baby = null; /* * Prevent overflowing the total number of genomes spawned per population. */ if (numSpawned < _params.NumGenomesToSpawn) { // Exclude the leader from numToSpawn. int numToSpawn = Mathf.RoundToInt(species.NumToSpawn()) - 1; numToSpawn = Mathf.Min(numToSpawn, _params.NumGenomesToSpawn - numSpawned); Debug.Log("spawning " + numToSpawn + " num indivudals for species " + species.ID() + ", best fitness: " + species.BestFitness()); while (numToSpawn-- > 0) { /* * Unless we have >2 members in the species crossover * can't be performed. */ if (species.NumMembers() == 1) { baby = new CGenome(species.Spawn()); } else { CGenome mum = species.Spawn(); if (Random.value < _params.CrossoverRate) { CGenome dad = species.Spawn(); int numAttempts = 5; // try to select a genome which is not the same as mum while (mum.ID() == dad.ID() && numAttempts-- > 0) { dad = species.Spawn(); } if (mum.ID() != dad.ID()) { baby = Crossover(mum, dad); } else { if (Random.value < 0.5f) { baby = new CGenome(dad); } else { baby = new CGenome(mum); } } } else { baby = new CGenome(mum); } } if (baby == null) { continue; } baby.SetID(++nextGenomeID); MutateBaby(baby); //EDIT me baby.SortGenes(); newPopulation.Add(baby); if (numSpawned++ >= _params.NumGenomesToSpawn) { numToSpawn = 0; break; } } } return(numSpawned); }
SpeciateGenomes() { bool addedToSpecies = false; for (int i = 0; i < m_Population.Count; i++) { CGenome genome = m_Population[i]; float bestCompatability = 1000; CSpecies bestSpecies = null; for (int j = 0; j < m_vecSpecies.Count; j++) { CSpecies species = m_vecSpecies[j]; float compatibility = genome.GetCompatibilityScore(species.Leader()); // if this individual is similar to this species leader add to species if (compatibility < bestCompatability) { bestCompatability = compatibility; bestSpecies = species; } } if (bestCompatability <= _params.CompatibilityThreshold) { bestSpecies.AddMember(genome); genome.SetSpecies(bestSpecies.ID()); addedToSpecies = true; } if (!addedToSpecies) { // we have not found a compatible species so a new one will be created m_vecSpecies.Add(new CSpecies(genome, nextSpeciesID++)); } addedToSpecies = false; } /* * Adjust the fitness for all members of the every species to take * into account fitness sharing and age of species. */ for (int i = 0; i < m_vecSpecies.Count; i++) { CSpecies species = m_vecSpecies[i]; species.AdjustFitnesses(); } /* * Calculate new adjusted total and average fitness for the population. */ for (int i = 0; i < m_Population.Count; i++) { CGenome genome = m_Population[i]; m_dTotFitAdj += genome.GetAdjustedFitness(); } m_dAvFitAdj = m_dTotFitAdj / m_Population.Count; }
SelectGenesToBreed(CGenome mum, CGenome dad, ParentType best, List <SLinkGene> babyGenes, List <int> neuronIDs) { List <SLinkGene> mumLinks = mum.GetLinks(); List <SLinkGene> dadLinks = dad.GetLinks(); using (IEnumerator <SLinkGene> mumEnumerator = mumLinks.GetEnumerator()) using (IEnumerator <SLinkGene> dadEnumerator = dadLinks.GetEnumerator()) { bool hasMumMore = mumEnumerator.MoveNext(); bool hasDadMore = dadEnumerator.MoveNext(); SLinkGene selectedGene = mumEnumerator.Current; while (hasMumMore || hasDadMore) { if (!hasMumMore && hasDadMore) { if (best == ParentType.Dad) { selectedGene = dadEnumerator.Current; } hasDadMore = dadEnumerator.MoveNext(); } else if (!hasDadMore && hasMumMore) { if (best == ParentType.Mum) { selectedGene = mumEnumerator.Current; } hasMumMore = mumEnumerator.MoveNext(); } else if (mumEnumerator.Current.InnovationID < dadEnumerator.Current.InnovationID) { if (best == ParentType.Mum) { selectedGene = mumEnumerator.Current; } hasMumMore = mumEnumerator.MoveNext(); } else if (dadEnumerator.Current.InnovationID < mumEnumerator.Current.InnovationID) { if (best == ParentType.Dad) { selectedGene = dadEnumerator.Current; } hasDadMore = dadEnumerator.MoveNext(); } else if (dadEnumerator.Current.InnovationID == mumEnumerator.Current.InnovationID) { if (Random.value < 0.5f) { selectedGene = mumEnumerator.Current; } else { selectedGene = dadEnumerator.Current; } hasMumMore = mumEnumerator.MoveNext(); hasDadMore = dadEnumerator.MoveNext(); } if (babyGenes.Count == 0) { babyGenes.Add(new SLinkGene(selectedGene)); } else { if (babyGenes[babyGenes.Count - 1].InnovationID != selectedGene.InnovationID) { babyGenes.Add(new SLinkGene(selectedGene)); } } AddNeuronID(selectedGene.FromNeuron, neuronIDs); AddNeuronID(selectedGene.ToNeuron, neuronIDs); } } }
CalculateTopologyDifference(out float numDisjoint, out float numExcess, out float numMatched, out float weightDiff, CGenome other) { numDisjoint = 0; numExcess = 0; numMatched = 0; weightDiff = 0; /* * Current position of the gene in both genomes. We increment the * position as we traverse the topology of the genomes. */ int g1 = 0; int g2 = 0; while (g1 < m_vecLinks.Count - 1 || g2 < other.m_vecLinks.Count - 1) { // more genes in genome1 than genome2 if (g1 == m_vecLinks.Count - 1) { g2++; numExcess++; continue; } // more gens in genome2 than genome1 if (g2 == other.m_vecLinks.Count - 1) { g1++; numExcess++; continue; } int id1 = m_vecLinks[g1].InnovationID; int id2 = other.m_vecLinks[g2].InnovationID; // compare innovation numbers if (id1 == id2) { g1++; g2++; numMatched++; weightDiff += Mathf.Abs((float)(m_vecLinks[g1].Weight - other.m_vecLinks[g2].Weight)); } if (id1 < id2) { g1++; numDisjoint++; } if (id1 > id2) { g2++; numDisjoint++; } } }