Esempio n. 1
0
        public static void Main(String[] args)
        {
            GeneticSelectionProcess <Population <TestIndividual <Boolean>, Boolean>, TestIndividual <Boolean>,
                                     Chromosome <Boolean>, Boolean, ProcessInformation> .Builder builder =
                new GeneticSelectionProcess <Population <TestIndividual <Boolean>, Boolean>, TestIndividual <Boolean>,
                                             Chromosome <Boolean>, Boolean, ProcessInformation> .Builder();

            Random rng = new Random();

            Int32 genomeSize            = 100;
            Int32 targetFitness         = 90;
            Int32 fitnessDeltaTolerance = 10;

            Int32  populationSize = 1000;
            Double mutationRate   = 0.01;

            GeneticSelectionProcess <Population <TestIndividual <Boolean>, Boolean>, TestIndividual <Boolean>,
                                     Chromosome <Boolean>, Boolean, ProcessInformation> process = builder
                                                                                                  .SetInitialPopulationSize(populationSize).UseDefaultConsoleLogger()
                                                                                                  .SetProcessInformationComposer(
                new ProcessInformationComposer <Population <TestIndividual <Boolean>, Boolean>, TestIndividual <Boolean>
                                                , Boolean>())
                                                                                                  .SetMatingFunction(
                new CrossOverMatingFunction <TestIndividual <Boolean>, Chromosome <Boolean>, Boolean>(3))
//                    new RandomCombinationMatingFunction<
//                        TestIndividual<Boolean>
//                        , Chromosome<Boolean>
//                        , Boolean>())
                                                                                                  .SetParentSelector(
                new SingleGroupFittestParentsSelector <Population <TestIndividual <Boolean>, Boolean>,
                                                       TestIndividual <Boolean>, Boolean>()).SetFitnessFunction(new TestFitnessFunction())
                                                                                                  .SetSurvivorSelector(
                new ReplaceLeastFitSelector <Population <TestIndividual <Boolean>, Boolean>, TestIndividual <Boolean>,
                                             Boolean>())
                                                                                                  .SetPopulationInitializer(
                new BooleanRandomPopulationInitializer <Population <TestIndividual <Boolean>, Boolean>,
                                                        TestIndividual <Boolean>, Chromosome <Boolean> >(genomeSize))
                                                                                                  .AddTerminationCondition(
                new FitnessTerminator <Population <TestIndividual <Boolean>, Boolean>, TestIndividual <Boolean>, Boolean
                                       >(targetFitness))
                                                                                                  .AddPopulationModifier(
                new RandomMutationModifier <Population <TestIndividual <Boolean>, Boolean>, TestIndividual <Boolean>,
                                            Boolean>(mutationRate, () => rng.Next(2) == 1)).Build();

            process.Initialize();
            process.RunUntilConvergence();

            IndividualWithFitness <TestIndividual <Boolean>, Boolean> fittest = process.GetPopulation().GetFittest();
            Double fittestFitness = fittest.GetFitness();

            Boolean[] fittestGenome = fittest.GetIndividual().GetChromosome().GetGenome();

            Console.WriteLine($"Max fitness {fittestFitness}");
            Console.WriteLine($"Genome {string.Join("", fittestGenome.Select(b => b ? 1 : 0))}");
            Console.WriteLine("Done");
        }
Esempio n. 2
0
        public void TrivialMaximizeTruesProcessShouldRun()
        {
            Random rng = new Random();

            Int32  genomeSize     = 100;
            Int32  targetFitness  = 90;
            Int32  populationSize = 100;
            Double mutationRate   = 0.01;

            var matingFunctions = new List <IMatingFunction <TestIndividual <Boolean>, Chromosome <Boolean>, Boolean> >
            {
                new CrossOverMatingFunction <TestIndividual <Boolean>, Chromosome <Boolean>, Boolean>(1)
                , new CrossOverMatingFunction <TestIndividual <Boolean>, Chromosome <Boolean>, Boolean>(3)
                , new RandomCombinationMatingFunction <TestIndividual <Boolean>, Chromosome <Boolean>, Boolean>()
            };

            foreach (IMatingFunction <TestIndividual <Boolean>, Chromosome <Boolean>, Boolean> matingFunction in
                     matingFunctions)
            {
                var builder =
                    new GeneticSelectionProcess <Population <TestIndividual <Boolean>, Boolean>, TestIndividual <Boolean>,
                                                 Chromosome <Boolean>, Boolean, ProcessInformation> .Builder();

                var process = builder.SetInitialPopulationSize(populationSize).UseDefaultConsoleLogger()
                              .SetProcessInformationComposer(
                    new ProcessInformationComposer <Population <TestIndividual <Boolean>, Boolean>,
                                                    TestIndividual <Boolean>, Boolean>()).SetMatingFunction(matingFunction)
                              .SetParentSelector(
                    new SingleGroupFittestParentsSelector <Population <TestIndividual <Boolean>, Boolean>,
                                                           TestIndividual <Boolean>, Boolean>()).SetFitnessFunction(new TestFitnessFunction())
                              .SetSurvivorSelector(
                    new ReplaceLeastFitSelector <Population <TestIndividual <Boolean>, Boolean>,
                                                 TestIndividual <Boolean>, Boolean>())
                              .SetPopulationInitializer(
                    new BooleanRandomPopulationInitializer <Population <TestIndividual <Boolean>, Boolean>,
                                                            TestIndividual <Boolean>, Chromosome <Boolean> >(genomeSize))
                              .AddTerminationCondition(
                    new FitnessTerminator <Population <TestIndividual <Boolean>, Boolean>, TestIndividual <Boolean>,
                                           Boolean>(targetFitness))
                              .AddPopulationModifier(
                    new RandomMutationModifier <Population <TestIndividual <Boolean>, Boolean>, TestIndividual <Boolean>
                                                , Boolean>(mutationRate, () => rng.Next(2) == 1)).Build();

                process.Initialize();
                process.RunUntilConvergence();

                IndividualWithFitness <TestIndividual <Boolean>, Boolean> fittest = process.GetPopulation().GetFittest();
                Double    fittestFitness = fittest.GetFitness();
                Boolean[] fittestGenome  = fittest.GetIndividual().GetChromosome().GetGenome();

                Double expectedFitness = fittestGenome.Select(b => b ? 1 : 0).Sum();

                Assert.True(fittestFitness >= 90);
                Assert.True(expectedFitness >= 90);
                Assert.True(expectedFitness.AreDoublesEqual(fittestFitness));

                IList <ProcessInformation> history = process.GetHistory();
                Assert.True(history.Count > 1);
                Assert.True(fittestFitness.AreDoublesEqual(history[history.Count - 1].FittestFitness));
            }
        }
        /// <summary>
        ///     Run a single generation of the process.
        /// </summary>
        /// <exception cref="InvalidOperationException"></exception>
        // ReSharper disable always PossibleNullReferenceException
        public void RunGeneration()
        {
            #region Validation

            if (_population == null)
            {
                throw new InvalidOperationException($"{nameof(_population)} was null");
            }
            if (_survivorSelector == null)
            {
                throw new InvalidOperationException($"{nameof(_survivorSelector)} was null");
            }
            if (_populationModifiers == null)
            {
                throw new InvalidOperationException($"{nameof(_populationModifiers)} was null");
            }
            if (_parentSelector == null)
            {
                throw new InvalidOperationException($"{nameof(_parentSelector)} was null");
            }
            if (_processInformationComposer == null)
            {
                throw new InvalidOperationException($"{nameof(_processInformationComposer)} was null");
            }

            #endregion

            _isRunning = true;

            UInt64 generationCount = _previousProcessInformation?.GetGeneration() ?? 0;
            LogDebug($"Starting generation {generationCount}");

            // Select parents to produce new generation of offspring.
            LogDebug("Selecting parents");

            IList <IEnumerable <TIndividual> > parentGroups = _parentSelector.GetParents(_population).ToList();

            // Log parents and their fitness.
            Int32 parentGroupCount = 0;
            foreach (IEnumerable <TIndividual> parentGroup in parentGroups)
            {
                Double         totalFitness  = 0;
                IList <String> parentStrings = new List <String>();
                foreach (TIndividual parent in parentGroup)
                {
                    IndividualWithFitness <TIndividual, TGene> individualParent =
                        _population.GetIndividualWithFitness(parent.GetGuid());

                    Double parentFitness = individualParent.GetFitness();
                    parentStrings.Add($"P {parent.GetGuidStringShort()} F {parentFitness}");
                    totalFitness += parentFitness;
                }

                LogInfo($"PG {parentGroupCount}, TF {totalFitness}, " + $"{string.Join(", ", parentStrings)}");

                parentGroupCount++;
            }

            if (parentGroups == null || !parentGroups.Any())
            {
                throw new InvalidOperationException("Failed to get parents");
            }

            // Mate selected parents, produce offspring.
            LogDebug("Mating parents; creating offspring");
            IList <TIndividual> offspring =
                parentGroups.Select(parentGroup => _matingFunction.Mate(parentGroup.ToList())).ToList();

            // Log unmodified offspring fitness.
            foreach (TIndividual individualOffspring in offspring)
            {
                Double offspringFitness = _fitnessFunction.CalculateFitness(individualOffspring);
                LogInfo($"O {individualOffspring.GetGuidStringShort()} F {offspringFitness}");
            }

            // Add new offspring to population.
            LogDebug("Selecting survivors; adding offspring to population");
            _survivorSelector.AddOffspring(_population, offspring);

            // Apply population modifiers to population.
            LogDebug("Applying population modifier");
            foreach (IPopulationModifier <TPopulation, TIndividual, TGene> populationModifier in _populationModifiers)
            {
                _population = populationModifier.ModifyPopulation(_population);
            }

            // Order by fitness.
            LogDebug("Ordering population by fitness");
            _population.OrderByFitness(_fitnessFunction);

            // Create information object.
            TProcessInformation currentGenerationProcessInformation =
                _processInformationComposer.ComposeProcessInformation(_previousProcessInformation, _population);

            AddToHistory(currentGenerationProcessInformation);

            LogInfo($"G{generationCount} TF {currentGenerationProcessInformation.GetTotalFitness()}");

            // Check if population has converged according to provided checks.
            if (!_hasConverged)
            {
                if (_terminationConditions.Any(terminationCondition =>
                                               terminationCondition.ShouldTerminate(_population, currentGenerationProcessInformation)))
                {
                    _hasConverged = true;
                    LogInfo("Population has converged! Termination condition met!");
                }
            }

            // Compose new process information object.
            _previousProcessInformation = currentGenerationProcessInformation;

            if (!_isRunningLocked)
            {
                _isRunning = false;
            }
        }