private void RecalcCentroids_GenomeById(Species <T>[] speciesArr, bool[] updateBits) { Parallel.ForEach(Enumerable.Range(0, speciesArr.Length).Where(i => updateBits[i]), _parallelOptions, (i) => { var species = speciesArr[i]; species.Centroid = _distanceMetric.CalculateCentroid(species.GenomeById.Values.Select(x => x.ConnectionGenes)); }); }
private void RecalcCentroids_GenomeById(Species <T>[] speciesArr, bool[] updateBits) { for (int i = 0; i < speciesArr.Length; i++) { if (updateBits[i]) { var species = speciesArr[i]; species.Centroid = _distanceMetric.CalculateCentroid(species.GenomeById.Values.Select(x => x.ConnectionGenes)); } } }
private void RecalcCentroids_GenomeById(Species <T>[] speciesArr, bool[] updateBits) { Parallel.ForEach( Enumerable.Range(0, speciesArr.Length).Where(i => updateBits[i]), _parallelOptions, () => new List <ConnectionGenes <T> >(), (speciesIdx, loopState, connGenesList) => { var species = speciesArr[speciesIdx]; SpeciationUtils.ExtractConnectionGenes(connGenesList, species.GenomeById); species.Centroid = _distanceMetric.CalculateCentroid(connGenesList); return(connGenesList); }, (connGenesList) => connGenesList.Clear()); }
public Species <T>[] InitialiseSpecies( IList <NeatGenome <T> > genomeList, int speciesCount, IRandomSource rng) { // Create an array of seed genomes, i.e. each of these genomes will become the initial // seed/centroid of one species. var seedGenomeList = new List <NeatGenome <T> >(speciesCount); // Create a list of genomes to select and remove seed genomes from. var remainingGenomes = new List <NeatGenome <T> >(genomeList); // Select first genome at random. seedGenomeList.Add(GetAndRemove(remainingGenomes, rng.Next(remainingGenomes.Count))); // Select all other seed genomes using k-means++ method. for (int i = 1; i < speciesCount; i++) { var seedGenome = GetSeedGenome(seedGenomeList, remainingGenomes, rng); seedGenomeList.Add(seedGenome); } // Create an array of species initialised with the chosen seed genomes. // Each species is created with an initial capacity that will reduce the need for memory // reallocation but that isn't too wasteful of memory. int initialCapacity = (genomeList.Count * 2) / speciesCount; var speciesArr = new Species <T> [speciesCount]; for (int i = 0; i < speciesCount; i++) { var seedGenome = seedGenomeList[i]; speciesArr[i] = new Species <T>(i, seedGenome.ConnectionGenes, initialCapacity); speciesArr[i].GenomeList.Add(seedGenome); } // Allocate all other genomes to the species centroid they are nearest too. Parallel.ForEach(remainingGenomes, _parallelOptions, genome => { var nearestSpeciesIdx = GetNearestSpecies(_distanceMetric, genome, speciesArr); var nearestSpecies = speciesArr[nearestSpeciesIdx]; lock (nearestSpecies.GenomeList) { nearestSpecies.GenomeList.Add(genome); } }); // Recalc species centroids. Parallel.ForEach(speciesArr, _parallelOptions, species => { species.Centroid = _distanceMetric.CalculateCentroid(species.GenomeList.Select(genome => genome.ConnectionGenes)); }); return(speciesArr); }
private void RecalcCentroids_GenomeById( Species <T>[] speciesArr, bool[] updateBits) { // Create a temporary, reusable, working list. var tmpConnGenes = new List <ConnectionGenes <T> >(); for (int i = 0; i < speciesArr.Length; i++) { if (updateBits[i]) { var species = speciesArr[i]; // Extract the ConnectionGenes<T> object from each genome in the GenomeById dictionary. SpeciationUtils.ExtractConnectionGenes(tmpConnGenes, species.GenomeById); // Calculate the centroid for the extracted connection genes. species.Centroid = _distanceMetric.CalculateCentroid(tmpConnGenes); } } tmpConnGenes.Clear(); }
private static NeatGenome <T> GetGenomeForEmptySpecies <T>( IDistanceMetric <T> distanceMetric, Species <T>[] speciesArr) where T : struct { // Get the species with the highest number of genomes. Species <T> species = speciesArr.Aggregate((x, y) => x.GenomeById.Count > y.GenomeById.Count ? x : y); // Get the genome furthest from the species centroid. var genome = species.GenomeById.Values.Aggregate((x, y) => distanceMetric.CalcDistance(species.Centroid, x.ConnectionGenes) > distanceMetric.CalcDistance(species.Centroid, y.ConnectionGenes) ? x : y); // Remove the genome from its current species. species.GenomeById.Remove(genome.Id); // Update the species centroid. species.Centroid = distanceMetric.CalculateCentroid(species.GenomeById.Values.Select(x => x.ConnectionGenes)); // Return the selected genome. return(genome); }
/// <summary> /// Recalculate the specie centroid based on the genomes currently in the specie. /// </summary> private CoordinateVector CalculateSpecieCentroid(Specie <TGenome> specie) { // Special case - 1 genome in specie (its position *is* the specie centroid). if (1 == specie.GenomeList.Count) { return(new CoordinateVector(specie.GenomeList[0].Position.CoordArray)); } // Create a temp list containing all of the genome positions. List <TGenome> genomeList = specie.GenomeList; int count = genomeList.Count; List <CoordinateVector> coordList = new List <CoordinateVector>(count); for (int i = 0; i < count; i++) { coordList.Add(genomeList[i].Position); } // The centroid calculation is a function of the distance metric. return(_distanceMetric.CalculateCentroid(coordList)); }
public static void ValidationTests( Species <double>[] speciesArr, IDistanceMetric <double> distanceMetric, int speciesCountExpected, List <NeatGenome <double> > fullGenomeList, bool validateNearestSpecies) { // Confirm correct number of species. Assert.Equal(speciesCountExpected, speciesArr.Length); // Confirm no empty species. int minSpeciesSize = speciesArr.Select(x => x.GenomeList.Count).Min(); Assert.True(minSpeciesSize > 0); // Get IDs of all genomes in species. var idSet = GetAllGenomeIds(speciesArr); // Confirm number of IDs equals number of genomes in main population list. Assert.Equal(fullGenomeList.Count, idSet.Count); // Confirm the genome list IDs match up with the genomes in the species. fullGenomeList.ForEach(x => Assert.Contains(x.Id, idSet)); // Confirm all species centroids are correct. Array.ForEach( speciesArr, x => Assert.Equal( 0.0, distanceMetric.CalcDistance(x.Centroid, distanceMetric.CalculateCentroid(x.GenomeList.Select(y => y.ConnectionGenes).ToList())))); if (validateNearestSpecies) { // Confirm all genomes are in the species with the nearest centroid. // Note. If there are two or more species that are equally near then we test that a genome is in one of those. Array.ForEach(speciesArr, species => species.GenomeList.ForEach(genome => Assert.Contains(species, GetNearestSpeciesList(genome, speciesArr, distanceMetric)))); } }
private static NeatGenome <T> GetGenomeForEmptySpecies <T>( IDistanceMetric <T> distanceMetric, Species <T>[] speciesArr, List <ConnectionGenes <T> > tmpPointList) where T : struct { // TODO: Select donor species stochastically from a pool of the largest species. // Get the species with the highest number of genomes. Species <T> species = speciesArr.Aggregate((x, y) => x.GenomeById.Count > y.GenomeById.Count ? x : y); // Get the genome furthest from the species centroid. double maxDistance = -1.0; NeatGenome <T>?chosenGenome = null; foreach (var genome in species.GenomeById.Values) { double distance = distanceMetric.CalcDistance(species.Centroid, genome.ConnectionGenes); if (distance > maxDistance) { maxDistance = distance; chosenGenome = genome; } } // Remove the genome from its current species. species.GenomeById.Remove(chosenGenome !.Id); // Extract the ConnectionGenes<T> object from each genome in the species' genome list. ExtractConnectionGenes(tmpPointList, species.GenomeById); // Calc and update species centroid. species.Centroid = distanceMetric.CalculateCentroid(tmpPointList); // Return the selected genome. return(chosenGenome); }
/// <summary> /// Group the provided genomes into new species. /// </summary> /// <param name="genomeList">The genomes to partition into groups/species.</param> /// <param name="speciesCount">The required number of species.</param> /// <param name="rng">Random source.</param> /// <returns>A new array of <see cref="Species{T}"/>, with each species containing a subset of the genomes from <paramref name="genomeList"/>.</returns> public Species <T>[] InitialiseSpecies( IList <NeatGenome <T> > genomeList, int speciesCount, IRandomSource rng) { // Create an array of seed genomes, i.e. each of these genomes will become the initial // seed/centroid of one species. var seedGenomeList = new List <NeatGenome <T> >(speciesCount); // Create a list of genomes to select and remove seed genomes from. var remainingGenomes = new List <NeatGenome <T> >(genomeList); // Select first genome at random. seedGenomeList.Add(GetAndRemove(remainingGenomes, rng.Next(remainingGenomes.Count))); // Select all other seed genomes using k-means++ method. for (int i = 1; i < speciesCount; i++) { var seedGenome = GetSeedGenome(seedGenomeList, remainingGenomes, rng); seedGenomeList.Add(seedGenome); } // Create an array of species initialised with the chosen seed genomes. // Each species is created with an initial capacity that will reduce the need for memory // reallocation but that isn't too wasteful of memory. int initialCapacity = (genomeList.Count * 2) / speciesCount; var speciesArr = new Species <T> [speciesCount]; for (int i = 0; i < speciesCount; i++) { var seedGenome = seedGenomeList[i]; speciesArr[i] = new Species <T>(i, seedGenome.ConnectionGenes, initialCapacity); speciesArr[i].GenomeList.Add(seedGenome); } // Allocate all other genomes to the species centroid they are nearest too. foreach (var genome in remainingGenomes) { var nearestSpeciesIdx = GetNearestSpecies(_distanceMetric, genome, speciesArr); speciesArr[nearestSpeciesIdx].GenomeList.Add(genome); } // Recalc species centroids. // Create a temporary, reusable, working list. var tmpConnGenes = new List <ConnectionGenes <T> >(); foreach (var species in speciesArr) { // Extract the ConnectionGenes<T> object from each genome in the species' genome list. ExtractConnectionGenes(tmpConnGenes, species.GenomeList); // Calculate the centroid for the extracted connection genes. species.Centroid = _distanceMetric.CalculateCentroid(tmpConnGenes); } tmpConnGenes.Clear(); return(speciesArr); }