/// <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);
    }
        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);
        }