예제 #1
0
        /// <summary>
        /// Speciates the offspring genomes in offspringList into the provided
        /// specieList. In contrast to SpeciateGenomes() offspringList is taken
        /// to be a list of new genomes (offspring) that should be added to
        /// existing species. That is, the species contain genomes that are not
        /// in offspringList that we wish to keep; typically these would be elite
        /// genomes that are the parents of the offspring.
        /// </summary>
        public void SpeciateOffspring(IList <TGenome> offspringList,
                                      IList <Specie <TGenome> > specieList)
        {
            // Each specie should contain at least one genome. We need at least
            // one existing genome per specie to act as a specie centroid in order
            // to define where the specie is within the encoding space.
            Debug.Assert(SpeciationUtils.TestPopulatedSpecies(specieList),
                         "SpeciateOffspring(IList<TGenome>,IList<Species<TGenome>>) called with an empty specie.");

            // Update the centroid of each specie. If we're adding offspring this
            // means that old genomes have been removed from the population and
            // therefore the centroids are out-of-date.
            foreach (Specie <TGenome> specie in specieList)
            {
                specie.Centroid = CalculateSpecieCentroid(specie);
            }

            // Allocate each offspring genome to the specie it is closest to.
            foreach (TGenome genome in offspringList)
            {
                Specie <TGenome> closestSpecie = FindClosestSpecie(genome, specieList);
                closestSpecie.GenomeList.Add(genome);
                genome.SpecieIdx = closestSpecie.Idx;
            }

            // Recalculate each specie's centroid now that we have additional
            // genomes in the specieList.
            foreach (Specie <TGenome> specie in specieList)
            {
                specie.Centroid = CalculateSpecieCentroid(specie);
            }

            // Accumulate *all* genomes into a flat genome list.
            int genomeCount = 0;

            foreach (Specie <TGenome> specie in specieList)
            {
                genomeCount += specie.GenomeList.Count;
            }

            List <TGenome> genomeList = new List <TGenome>(genomeCount);

            foreach (Specie <TGenome> specie in specieList)
            {
                genomeList.AddRange(specie.GenomeList);
            }

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

            Debug.Assert(SpeciationUtils.PerformIntegrityCheck(specieList));
        }
예제 #2
0
        /// <summary>
        /// Speciates the offspring genomes in offspringList into the provided specieList. In contrast to
        /// SpeciateGenomes() offspringList is taken to be a list of new genomes (offspring) that should be
        /// added to existing species. That is, the species contain genomes that are not in offspringList
        /// that we wish to keep; typically these would be elite genomes that are the parents of the
        /// offspring.
        /// </summary>
        public void SpeciateOffspring(IList <TGenome> offspringList, IList <Specie <TGenome> > specieList)
        {
            // Each specie should contain at least one genome. We need at least one existing genome per specie to act
            // as a specie centroid in order to define where the specie is within the encoding space.
            Debug.Assert(SpeciationUtils.TestPopulatedSpecies(specieList), "SpeciateOffspring(IList<TGenome>,IList<Species<TGenome>>) called with an empty specie.");

            // Update the centroid of each specie. If we're adding offspring this means that old genomes
            // have been removed from the population and therefore the centroids are out-of-date.
            Parallel.ForEach(specieList, _parallelOptions, delegate(Specie <TGenome> specie) {
                specie.Centroid = CalculateSpecieCentroid(specie);
            });

            // Allocate each offspring genome to the specie it is closest to.
            Parallel.ForEach(offspringList, _parallelOptions, delegate(TGenome genome)
            {
                Specie <TGenome> closestSpecie = FindClosestSpecie(genome, specieList);
                lock (closestSpecie.GenomeList) {
                    // TODO: Consider using ConcurrentQueue here (and elsewhere in this class).
                    closestSpecie.GenomeList.Add(genome);
                }
                genome.SpecieIdx = closestSpecie.Idx;
            });

            // Recalculate each specie's centroid now that we have additional genomes in the specieList.
            Parallel.ForEach(specieList, _parallelOptions, delegate(Specie <TGenome> specie) {
                specie.Centroid = CalculateSpecieCentroid(specie);
            });

            // Accumulate *all* genomes into a flat genome list.
            int genomeCount = 0;

            foreach (Specie <TGenome> specie in specieList)
            {
                genomeCount += specie.GenomeList.Count;
            }

            List <TGenome> genomeList = new List <TGenome>(genomeCount);

            foreach (Specie <TGenome> specie in specieList)
            {
                genomeList.AddRange(specie.GenomeList);
            }

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

            Debug.Assert(SpeciationUtils.TestPopulatedSpecies(specieList), "Speciation must allocate at least one genome to each species.");
        }
예제 #3
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;

            Parallel.For(specieCount, genomeCount, _parallelOptions, delegate(int i)
            {
                TGenome genome = genomeList[i];
                Specie <TGenome> closestSpecie = FindClosestSpecie(genome, specieList);
                genome.SpecieIdx = closestSpecie.Idx;

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

            // Recalculate each specie's centroid.
            Parallel.ForEach(specieList, _parallelOptions, delegate(Specie <TGenome> specie) {
                specie.Centroid = CalculateSpecieCentroid(specie);
            });

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

            Debug.Assert(SpeciationUtils.TestPopulatedSpecies(specieList), "Speciation must allocate at least one genome to each specie.");
        }
예제 #4
0
        /// <summary>
        /// Speciates the offspring genomes in genomeList into the provided species. In contrast to
        /// SpeciateGenomes() genomeList is taken to be a list of new genomes (e.g. offspring) that should be
        /// added to existing species. That is, the species contain genomes that are not in genomeList
        /// that we wish to keep; typically these would be elite genomes that are the parents of the
        /// offspring.
        /// </summary>
        public void SpeciateOffspring(IList <TGenome> genomeList, IList <Specie <TGenome> > specieList)
        {
            // Each specie should contain at least one genome. We need at least one existing genome per specie to act
            // as a specie centroid in order to define where the specie is within the encoding space.
            Debug.Assert(SpeciationUtils.TestPopulatedSpecies(specieList), "SpeciateOffspring(IList<TGenome>,IList<Species<TGenome>>) called with an empty specie.");

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

            SharpNeat.Utility.Utilities.Shuffle(gList, _rng);

            // Count how many genomes we have in total.
            int genomeCount      = gList.Count;
            int totalGenomeCount = genomeCount;

            foreach (Specie <TGenome> specie in specieList)
            {
                totalGenomeCount += specie.GenomeList.Count;
            }

            // We attempt to 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 specieCount      = specieList.Count;
            int genomesPerSpecie = totalGenomeCount / specieCount;

            // Sort species, smallest first. We must make a copy of specieList to do this; Species must remain at
            // the correct index in the main specieList. The principle here is that we wish to ensure that genomes are
            // allocated to smaller species in preference to larger species, this is motivated by the desire to create
            // evenly sized species.
            List <Specie <TGenome> > sList = new List <Specie <TGenome> >(specieList);

            sList.Sort(delegate(Specie <TGenome> x, Specie <TGenome> y)
            {               // We use the difference in size where we aren't expecting that diff value to overflow the range of an int.
                return(x.GenomeList.Count - y.GenomeList.Count);
            });

            // Add genomes into each specie in turn until they each reach genomesPerSpecie in size.
            int genomeIdx = 0;

            for (int i = 0; i < specieCount && genomeIdx < genomeCount; i++)
            {
                Specie <TGenome> specie = sList[i];
                int fillcount           = genomesPerSpecie - specie.GenomeList.Count;

                if (fillcount <= 0)
                {   // We may encounter species with more than genomesPerSpecie genomes. Since we have
                    // ordered the species by size we break out of this loop and allocate the remaining
                    // genomes randomly.
                    break;
                }

                // Don't allocate more genomes than there are remaining in genomeList.
                fillcount = Math.Min(fillcount, genomeCount - genomeIdx);

                // Allocate memory for the genomes we are about to allocate;
                // This eliminates potentially having to dynamically resize the list one or more times.
                if (specie.GenomeList.Capacity < specie.GenomeList.Count + fillcount)
                {
                    specie.GenomeList.Capacity = specie.GenomeList.Count + fillcount;
                }

                // genomeIdx test not required. Already taken into account by fillCount.
                for (int j = 0; j < fillcount; j++)
                {
                    gList[genomeIdx].SpecieIdx = specie.Idx;
                    specie.GenomeList.Add(gList[genomeIdx++]);
                }
            }

            // Evenly allocate any remaining genomes.
            int[] specieIdxArr = new int[specieCount];
            for (int i = 0; i < specieCount; i++)
            {
                specieIdxArr[i] = i;
            }
            SharpNeat.Utility.Utilities.Shuffle(specieIdxArr, _rng);

            for (int i = 0; i < specieCount && genomeIdx < genomeCount; i++, genomeIdx++)
            {
                int specieIdx = specieIdxArr[i];
                gList[genomeIdx].SpecieIdx = specieIdx;
                specieList[specieIdx].GenomeList.Add(gList[genomeIdx]);
            }

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