/// <summary>
        /// Speciates the genomes in genomeList into the provided species. It is assumed that
        /// the genomeList represents all of the required genomes and that the species are currently empty.
        ///
        /// This method can be used for initialization or completely respeciating an existing genome population.
        /// </summary>
        public void SpeciateGenomes(IList <TGenome> genomeList, IList <Specie <TGenome> > specieList)
        {
            Debug.Assert(SpeciationUtils.TestEmptySpecies(specieList), "SpeciateGenomes(IList<TGenome>,IList<Species<TGenome>>) called with non-empty species");
            Debug.Assert(genomeList.Count >= specieList.Count, string.Format("SpeciateGenomes(IList<TGenome>,IList<Species<TGenome>>). Specie count [{0}] is greater than genome count [{1}].", specieList.Count, genomeList.Count));

            // Make a copy of genomeList and shuffle the items.
            List <TGenome> gList = new List <TGenome>(genomeList);

            Utilities.Shuffle(gList, _rng);

            // We evenly distribute genomes between species.
            // Calc how many genomes per specie. Baseline number given by integer division rounding down (by truncating fractional part).
            // This is guaranteed to be at least 1 because genomeCount >= specieCount.
            int genomeCount      = genomeList.Count;
            int specieCount      = specieList.Count;
            int genomesPerSpecie = genomeCount / specieCount;

            // Allocate genomes to species.
            int genomeIdx = 0;

            for (int i = 0; i < specieCount; i++)
            {
                Specie <TGenome> specie = specieList[i];
                for (int j = 0; j < genomesPerSpecie; j++, genomeIdx++)
                {
                    specie.GenomeList.Add(gList[genomeIdx]);
                }
            }

            // Evenly allocate any remaining genomes.
            for (int i = 0; i < specieCount && genomeIdx < genomeCount; i++, genomeIdx++)
            {
                specieList[i].GenomeList.Add(gList[genomeIdx]);
            }
        }
예제 #2
0
        /// <summary>
        /// Speciates the genomes in genomeList into the provided specieList.
        /// It is assumed that the genomeList represents all of the required
        /// genomes and that the species are currently empty.
        ///
        /// This method can be used for initialization or completely respeciating
        /// an existing genome population.
        /// </summary>
        public void SpeciateGenomes(IList <TGenome> genomeList,
                                    IList <Specie <TGenome> > specieList)
        {
            Debug.Assert(SpeciationUtils.TestEmptySpecies(specieList),
                         "SpeciateGenomes(IList<TGenome>,IList<Species<TGenome>>) called with non-empty species");
            Debug.Assert(genomeList.Count >= specieList.Count,
                         string.Format("SpeciateGenomes(IList<TGenome>,IList<Species<TGenome>>). Species count [{0}] is greater than genome count [{1}].",
                                       specieList.Count, genomeList.Count));

            // Randomly allocate the first k genomes to their own specie.
            // Because there is only one genome in these species each genome
            // effectively represents a specie centroid. This is necessary to
            // ensure we get k specieList. If we randomly assign all genomes to
            // species from the outset and then calculate centroids then
            // typically some of the species become empty. This approach ensures
            // that each species will have at least one genome - because that
            // genome is the specie centroid and therefore has distance of zero
            // from the centroid (itself).
            int specieCount = specieList.Count;

            for (int i = 0; i < specieCount; i++)
            {
                Specie <TGenome> specie = specieList[i];
                genomeList[i].SpecieIdx = specie.Idx;
                specie.GenomeList.Add(genomeList[i]);

                // Just set the specie centroid directly.
                specie.Centroid = genomeList[i].Position;
            }

            // Now allocate the remaining genomes based on their distance from the centroids.
            int genomeCount = genomeList.Count;

            for (int i = specieCount; i < genomeCount; i++)
            {
                TGenome          genome        = genomeList[i];
                Specie <TGenome> closestSpecie = FindClosestSpecie(genome, specieList);
                genome.SpecieIdx = closestSpecie.Idx;
                closestSpecie.GenomeList.Add(genome);
            }

            // Recalculate each specie's centroid.
            foreach (Specie <TGenome> specie in specieList)
            {
                specie.Centroid = CalculateSpecieCentroid(specie);
            }

            // Perform the main k-means loop until convergence.
            SpeciateUntilConvergence(genomeList, specieList);

            Debug.Assert(SpeciationUtils.PerformIntegrityCheck(specieList));
        }