private static void AllocateEliteSelectionOffspringCounts( Species <T> species, NeatEvolutionAlgorithmSettings eaSettings, bool isBestGenomeSpecies, IRandomSource rng) { SpeciesStats stats = species.Stats; // Special case - zero target size. if (stats.TargetSizeInt == 0) { stats.EliteSizeInt = 0; stats.OffspringCount = 0; stats.OffspringAsexualCount = 0; stats.OffspringSexualCount = 0; stats.SelectionSizeInt = 0; return; } // Calculate the elite size as a proportion of the current species size. // Note. We discretize the real size with a probabilistic handling of the fractional part. double eliteSizeReal = species.GenomeList.Count * eaSettings.ElitismProportion; int eliteSizeInt = (int)NumericsUtils.ProbabilisticRound(eliteSizeReal, rng); // Ensure eliteSizeInt is no larger than the current target size. (I.e. the value was // calculated as a proportion of the current size, not the new target size). stats.EliteSizeInt = Math.Min(eliteSizeInt, stats.TargetSizeInt); // Special case: ensure the species with the best genome preserves that genome. // Note. This is done even for a target size of one, which would mean that no offspring are // produced from the best genome, apart from the (usually small) chance of a cross-species mating. if (isBestGenomeSpecies && stats.EliteSizeInt == 0) { Debug.Assert(stats.TargetSizeInt != 0, "Zero target size assigned to specie that contains the best genome."); stats.EliteSizeInt = 1; } // Determine how many offspring to produce for the species. stats.OffspringCount = stats.TargetSizeInt - stats.EliteSizeInt; // Determine the split between asexual and sexual reproduction. Again using probabilistic // rounding to compensate for any rounding bias. double offspringAsexualCountReal = stats.OffspringCount * eaSettings.OffspringAsexualProportion; stats.OffspringAsexualCount = (int)NumericsUtils.ProbabilisticRound(offspringAsexualCountReal, rng); stats.OffspringSexualCount = stats.OffspringCount - stats.OffspringAsexualCount; // Calculate the selectionSize. The number of the species' fittest genomes that are selected from // to create offspring. // We ensure this is at least one; if TargetSizeInt is zero then it doesn't matter because no genomes will be // selected from this species to produce offspring, except for cross-species mating, hence the minimum of one is // a useful general approach. double selectionSizeReal = species.GenomeList.Count * eaSettings.SelectionProportion; stats.SelectionSizeInt = Math.Max(1, (int)NumericsUtils.ProbabilisticRound(selectionSizeReal, rng)); }
/// <summary> /// Copy constructor. /// </summary> /// <param name="copyFrom">The settings object to copy.</param> public NeatEvolutionAlgorithmSettings(NeatEvolutionAlgorithmSettings copyFrom) { this.SpeciesCount = copyFrom.SpeciesCount; this.ElitismProportion = copyFrom.ElitismProportion; this.SelectionProportion = copyFrom.SelectionProportion; this.OffspringAsexualProportion = copyFrom.OffspringAsexualProportion; this.OffspringSexualProportion = copyFrom.OffspringSexualProportion; this.InterspeciesMatingProportion = copyFrom.InterspeciesMatingProportion; this.StatisticsMovingAverageHistoryLength = copyFrom.StatisticsMovingAverageHistoryLength; }
/// <summary> /// Construct a new instance. /// </summary> /// <param name="eaSettings">NEAT evolution algorithm settings.</param> /// <param name="evaluator">An evaluator of lists of genomes.</param> /// <param name="speciationStrategy">Speciation strategy.</param> /// <param name="population">An initial population of genomes.</param> /// <param name="complexityRegulationStrategy">Complexity regulation strategy.</param> /// <param name="reproductionAsexualSettings">Asexual reproduction settings.</param> /// <param name="reproductionSexualSettings">Sexual reproduction settings.</param> /// <param name="weightMutationScheme">Connection weight mutation scheme.</param> /// <param name="rng">Random source.</param> public NeatEvolutionAlgorithm( NeatEvolutionAlgorithmSettings eaSettings, IGenomeListEvaluator <NeatGenome <T> > evaluator, ISpeciationStrategy <NeatGenome <T>, T> speciationStrategy, NeatPopulation <T> population, IComplexityRegulationStrategy complexityRegulationStrategy, NeatReproductionAsexualSettings reproductionAsexualSettings, NeatReproductionSexualSettings reproductionSexualSettings, WeightMutationScheme <T> weightMutationScheme, IRandomSource rng) { _eaSettingsCurrent = eaSettings ?? throw new ArgumentNullException(nameof(eaSettings)); _eaSettingsComplexifying = eaSettings; _eaSettingsSimplifying = eaSettings.CreateSimplifyingSettings(); _evaluator = evaluator ?? throw new ArgumentNullException(nameof(evaluator)); _speciationStrategy = speciationStrategy ?? throw new ArgumentNullException(nameof(speciationStrategy)); _pop = population ?? throw new ArgumentNullException(nameof(population)); _complexityRegulationStrategy = complexityRegulationStrategy ?? throw new ArgumentNullException(nameof(complexityRegulationStrategy)); if (reproductionAsexualSettings == null) { throw new ArgumentNullException(nameof(reproductionAsexualSettings)); } if (reproductionSexualSettings == null) { throw new ArgumentNullException(nameof(reproductionSexualSettings)); } _rng = rng; _genomeComparerDescending = new GenomeComparerDescending(evaluator.FitnessComparer); if (eaSettings.SpeciesCount > population.PopulationSize) { throw new ArgumentException("Species count is higher then the population size."); } _generationSeq = new Int32Sequence(); _reproductionAsexual = new NeatReproductionAsexual <T>( _pop.MetaNeatGenome, _pop.GenomeBuilder, _pop.GenomeIdSeq, population.InnovationIdSeq, _generationSeq, _pop.AddedNodeBuffer, reproductionAsexualSettings, weightMutationScheme); _reproductionSexual = new NeatReproductionSexual <T>( _pop.MetaNeatGenome, _pop.GenomeBuilder, _pop.GenomeIdSeq, _generationSeq, reproductionSexualSettings); _offspringBuilder = new OffspringBuilder <T>( _reproductionAsexual, _reproductionSexual, eaSettings.InterspeciesMatingProportion, evaluator.FitnessComparer); }
/// <summary> /// Calculate and update a number of statistical values and target size values on each species in the givben population. /// </summary> /// <param name="pop">The population to update species statistics on.</param> /// <param name="eaSettings">Evolution algorithm settings.</param> /// <param name="rng">Random source.</param> public static void CalcAndStoreSpeciesStats( NeatPopulation <T> pop, NeatEvolutionAlgorithmSettings eaSettings, IRandomSource rng) { // Calc and store the mean fitness of each species. CalcAndStoreSpeciesFitnessMeans(pop); // Calc and store the target size of each species (based on the NEAT fitness sharing method). SpeciesAllocationCalcs <T> .CalcAndStoreSpeciesAllocationSizes(pop, eaSettings, rng); }
/// <summary> /// Calc and store species target sizes based on relative mean fitness of each species, i.e. as per NEAT fitness sharing method. /// Then calc and store the elite, selection and offspring allocations/counts, per species. /// </summary> public static void CalcAndStoreSpeciesAllocationSizes( NeatPopulation <T> pop, NeatEvolutionAlgorithmSettings eaSettings, IRandomSource rng) { // Calculate the new target size of each species using fitness sharing. CalcAndStoreSpeciesTargetSizes(pop, rng); // Calculate elite, selection and offspring counts, per species. CalculateAndStoreEliteSelectionOffspringCounts(pop, eaSettings, rng); }
/// <summary> /// Creates a new settings object based on the current settings object, but modified to be suitable for use when /// the evolution algorithm is in simplifying mode. /// </summary> /// <returns>A new instance of <see cref="NeatEvolutionAlgorithmSettings"/>.</returns> public NeatEvolutionAlgorithmSettings CreateSimplifyingSettings() { // Clone the current settings object. var settings = new NeatEvolutionAlgorithmSettings(this) { OffspringAsexualProportion = 1.0, OffspringSexualProportion = 0.0 }; return(settings); }
/// <summary> /// Read json into a target instance of <see cref="NeatEvolutionAlgorithmSettings"/>. /// Settings that are present are read and set on the target settings object; all other settings /// remain unchanged on the target object. /// </summary> /// <param name="target">The target settings object to store the read values on.</param> /// <param name="jobj">The json object to read from.</param> public static void Read( NeatEvolutionAlgorithmSettings target, JObject jobj) { ReadIntOptional(jobj, "speciesCount", x => target.SpeciesCount = x); ReadDoubleOptional(jobj, "elitismProportion", x => target.ElitismProportion = x); ReadDoubleOptional(jobj, "selectionProportion", x => target.SelectionProportion = x); ReadDoubleOptional(jobj, "offspringAsexualProportion", x => target.OffspringAsexualProportion = x); ReadDoubleOptional(jobj, "offspringSexualProportion", x => target.OffspringSexualProportion = x); ReadDoubleOptional(jobj, "interspeciesMatingProportion", x => target.InterspeciesMatingProportion = x); ReadIntOptional(jobj, "statisticsMovingAverageHistoryLength", x => target.StatisticsMovingAverageHistoryLength = x); }
/// <summary> /// Construct a new instance. /// </summary> /// <param name="eaSettings">NEAT evolution algorithm settings.</param> /// <param name="evaluator">An evaluator of lists of genomes.</param> /// <param name="speciationStrategy">Speciation strategy.</param> /// <param name="population">An initial population of genomes.</param> /// <param name="reproductionAsexualSettings">Asexual reproduction settings.</param> /// <param name="reproductionSexualSettings">Sexual reproduction settings.</param> /// <param name="weightMutationScheme">Connection weight mutation scheme.</param> public NeatEvolutionAlgorithm( NeatEvolutionAlgorithmSettings eaSettings, IGenomeListEvaluator <NeatGenome <T> > evaluator, ISpeciationStrategy <NeatGenome <T>, T> speciationStrategy, NeatPopulation <T> population, NeatReproductionAsexualSettings reproductionAsexualSettings, NeatReproductionSexualSettings reproductionSexualSettings, WeightMutationScheme <T> weightMutationScheme) : this(eaSettings, evaluator, speciationStrategy, population, reproductionAsexualSettings, reproductionSexualSettings, weightMutationScheme, RandomDefaults.CreateRandomSource()) { }
/// <summary> /// For each species, allocate the EliteSizeInt, OffspringCount (broken down into OffspringAsexualCount and OffspringSexualCount), /// and SelectionSizeInt values. /// </summary> /// <param name="pop"></param> /// <param name="eaSettings"></param> /// <param name="rng"></param> private static void CalculateAndStoreEliteSelectionOffspringCounts( NeatPopulation <T> pop, NeatEvolutionAlgorithmSettings eaSettings, IRandomSource rng) { Species <T>[] speciesArr = pop.SpeciesArray; // Loop the species, calculating and storing the various size/count properties. for (int i = 0; i < speciesArr.Length; i++) { bool isBestGenomeSpecies = (pop.BestGenomeSpeciesIdx == i); AllocateEliteSelectionOffspringCounts(speciesArr[i], eaSettings, isBestGenomeSpecies, rng); } }