/// <summary>
        /// Merge new genomes into an existing set of species.
        /// </summary>
        /// <param name="genomeList">A list of genomes that have not yet been assigned a species.</param>
        /// <param name="speciesArr">An array of pre-existing species</param>
        /// <param name="rng">Random source.</param>
        public void SpeciateAdd(IList <NeatGenome <T> > genomeList, Species <T>[] speciesArr, IRandomSource rng)
        {
            // Create a temporary working array of species modification bits.
            var updateBits = new bool[speciesArr.Length];

            // Allocate the new genomes to the species centroid they are nearest too.
            Parallel.ForEach(genomeList, _parallelOptions, (genome) =>
            {
                var nearestSpeciesIdx = SpeciationUtils.GetNearestSpecies(_distanceMetric, genome, speciesArr);
                var nearestSpecies    = speciesArr[nearestSpeciesIdx];

                lock (nearestSpecies.GenomeList) {
                    nearestSpecies.GenomeList.Add(genome);
                }

                // Set the modification bit for the species.
                updateBits[nearestSpeciesIdx] = true;
            });

            // Recalc the species centroids for species that have been modified.
            RecalcCentroids_GenomeList(speciesArr, updateBits);

            // Run the k-means algorithm.
            RunKMeans(speciesArr);
        }
Ejemplo n.º 2
0
    private int KMeansIteration(Species <T>[] speciesArr, bool[] updateBits)
    {
        int reallocCount = 0;

        Array.Clear(updateBits, 0, updateBits.Length);

        // Loop species.
        // Note. The nested parallel loop here is intentional and should give good thread concurrency in the general case.
        // For more info see: "Is it OK to use nested Parallel.For loops?"
        // https://blogs.msdn.microsoft.com/pfxteam/2012/03/14/is-it-ok-to-use-nested-parallel-for-loops/

        Parallel.For(0, speciesArr.Length, _parallelOptions, (speciesIdx) =>
        {
            var species = speciesArr[speciesIdx];

            // Loop genomes in the current species.
            Parallel.ForEach(species.GenomeById.Values, _parallelOptions, (genome) =>
            {
                // Determine the species centroid the genome is nearest to.
                var nearestSpeciesIdx = SpeciationUtils.GetNearestSpecies(_distanceMetric, genome, speciesArr);

                // If the nearest species is not the species the genome is currently in then move the genome.
                if (nearestSpeciesIdx != speciesIdx)
                {
                    // Move genome.
                    // Note. We can't modify species.GenomeById while we are enumerating through it, therefore we record the IDs
                    // of the genomes to be removed and remove them once we leave the enumeration loop.
                    lock (species.PendingRemovesList)
                    {
                        species.PendingRemovesList.Add(genome.Id);
                    }

                    var nearestSpecies = speciesArr[nearestSpeciesIdx];
                    lock (nearestSpecies.PendingAddsList)
                    {
                        nearestSpecies.PendingAddsList.Add(genome);
                    }

                    // Set the modification bits for the two species.
                    updateBits[speciesIdx]        = true;
                    updateBits[nearestSpeciesIdx] = true;

                    // Track the number of re-allocations.
                    Interlocked.Increment(ref reallocCount);
                }
            });
        });

        // Complete moving of genomes to their new species.
        Parallel.ForEach(speciesArr, _parallelOptions, (species) => species.CompletePendingMoves());

        // Recalc the species centroids for species that have been modified.
        RecalcCentroids_GenomeById(speciesArr, updateBits);

        return(reallocCount);
    }
Ejemplo n.º 3
0
        private void KMeansComplete(Species <T>[] speciesArr)
        {
            // Check for empty species (this can happen with k-means), and if there are any then
            // move genomes into those empty species.
            var emptySpeciesArr = speciesArr.Where(x => x.GenomeById.Count == 0).ToArray();

            if (emptySpeciesArr.Length != 0)
            {
                SpeciationUtils.PopulateEmptySpecies(_distanceMetric, emptySpeciesArr, speciesArr);
            }

            // Transfer all genomes from GenomeById to GenomeList.
            Parallel.ForEach(speciesArr, _parallelOptions, species => species.FlushWorkingDictionary());
        }
Ejemplo n.º 4
0
 private void RecalcCentroids_GenomeList(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.GenomeList);
         species.Centroid = _distanceMetric.CalculateCentroid(connGenesList);
         return(connGenesList);
     },
         (connGenesList) => connGenesList.Clear());
 }
        private int KMeansIteration(Species <T>[] speciesArr, bool[] updateBits)
        {
            int reallocCount = 0;

            Array.Clear(updateBits, 0, updateBits.Length);

            // Loop species.
            for (int speciesIdx = 0; speciesIdx < speciesArr.Length; speciesIdx++)
            {
                var species = speciesArr[speciesIdx];

                // Loop genomes in the current species.
                foreach (var genome in species.GenomeById.Values)
                {
                    // Determine the species centroid the genome is nearest to.
                    var nearestSpeciesIdx = SpeciationUtils.GetNearestSpecies(_distanceMetric, genome, speciesArr);

                    // If the nearest species is not the species the genome is currently in then move the genome.
                    if (nearestSpeciesIdx != speciesIdx)
                    {
                        // Move genome.
                        // Note. We can't modify species.GenomeById while we are enumerating through it, therefore we record the IDs
                        // of the genomes to be removed and remove them once we leave the enumeration loop.
                        species.PendingRemovesList.Add(genome.Id);
                        speciesArr[nearestSpeciesIdx].PendingAddsList.Add(genome);

                        // Set the modification bits for the two species.
                        updateBits[speciesIdx]        = true;
                        updateBits[nearestSpeciesIdx] = true;

                        // Track the number of re-allocations.
                        reallocCount++;
                    }
                }
            }

            // Complete moving of genomes to their new species.
            foreach (var species in speciesArr)
            {
                species.CompletePendingMoves();
            }

            // Recalc the species centroids for species that have been modified.
            RecalcCentroids_GenomeById(speciesArr, updateBits);

            return(reallocCount);
        }
Ejemplo n.º 6
0
        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];

                // Extract the ConnectionGenes<T> object from each genome in the GenomeById dictionary.
                SpeciationUtils.ExtractConnectionGenes(connGenesList, species.GenomeById);

                // Calculate the centroid for the extracted connection genes.
                species.Centroid = _distanceMetric.CalculateCentroid(connGenesList);
                return(connGenesList);
            },
                (connGenesList) => connGenesList.Clear());
        }
    private void RecalcCentroids_GenomeList(
        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 GenomeList.
                SpeciationUtils.ExtractConnectionGenes(tmpConnGenes, species.GenomeList);

                // Calculate the centroid for the extracted connection genes.
                species.Centroid = _distanceMetric.CalculateCentroid(tmpConnGenes);
            }
        }

        tmpConnGenes.Clear();
    }