Ejemplo n.º 1
0
        public void SelectChromosomes_Generation_ChromosomesZeroFitness()
        {
            var target = new RankSelection();
            var c1     = Substitute.ForPartsOf <ChromosomeBase>(2);

            c1.Fitness = 0;

            var c2 = Substitute.ForPartsOf <ChromosomeBase>(2);

            c2.Fitness = 0;

            var c3 = Substitute.ForPartsOf <ChromosomeBase>(2);

            c3.Fitness = 0;

            var c4 = Substitute.ForPartsOf <ChromosomeBase>(2);

            c4.Fitness = 0;

            var generation = new Generation(1, new List <IChromosome>()
            {
                c1, c2, c3, c4
            });

            var actual = target.SelectChromosomes(2, generation);

            Assert.AreEqual(2, actual.Count);
        }
        public void TestMethod()
        {
            var arr1 = new double[] { 10, 3, 18, -1, 20, 10, 3 }.ToList();
            var arr2 = new double[] { 15, 7, 0, 10, 25, 9 }.ToList();

            RankSelection rs = new RankSelection();
            var           fstSelectionNumber  = rs.AddSelection(arr1);
            var           scndSelectionNumber = rs.AddSelection(arr2);
        }
Ejemplo n.º 3
0
        public void SelectChromosomes_NullGeneration_Exception()
        {
            var target = new RankSelection();

            var actual = Assert.Catch <ArgumentNullException>(() =>
            {
                target.SelectChromosomes(2, null);
            });

            Assert.AreEqual("generation", actual.ParamName);
        }
Ejemplo n.º 4
0
        public void SelectChromosomes_InvalidNumber_Exception()
        {
            var target = new RankSelection();

            Assert.Catch <ArgumentOutOfRangeException>(() =>
            {
                target.SelectChromosomes(-1, null);
            }, "The number of selected chromosomes should be at least 2.");

            Assert.Catch <ArgumentOutOfRangeException>(() =>
            {
                target.SelectChromosomes(0, null);
            }, "The number of selected chromosomes should be at least 2.");

            Assert.Catch <ArgumentOutOfRangeException>(() =>
            {
                target.SelectChromosomes(1, null);
            }, "The number of selected chromosomes should be at least 2.");
        }
Ejemplo n.º 5
0
        public void SelectChromosomes_NullFitness_Exception()
        {
            var target     = new RankSelection();
            var generation = new Generation(1, new List <IChromosome>
            {
                new TspChromosome(10),
                new TspChromosome(10),
                new TspChromosome(10),
                new TspChromosome(10),
                new TspChromosome(10)
            });

            var actual = Assert.Catch <SelectionException>(() =>
            {
                target.SelectChromosomes(2, generation);
            });

            Assert.AreEqual("RankSelection: There are chromosomes with null fitness.", actual.Message);
        }
        public override double GetCoef()
        {
            var xRanged = new RankSelection();

            xRanged.AddSelection(x);

            var yRanged = new RankSelection();

            yRanged.AddSelection(y);

            double coef = 0;

            List <PointD> unionSeriaSortedByX =
                xRanged.ranks.Zip(yRanged.ranks.ToList(), (x, y) => new PointD(x, y)).OrderBy(p => p.X).ToList();

            List <double> rx = unionSeriaSortedByX.Select(p => p.X).ToList();
            List <double> ry = unionSeriaSortedByX.Select(p => p.Y).ToList();

            unionSeriaSortedByX.Select(p => p.X).ToList();
            double S = 0;

            for (int i = 0; i < N - 1; i++)
            {
                for (int j = i + 1; j < N; j++)
                {
                    if (rx[i] != rx[j])
                    {
                        S += ry[j].CompareTo(ry[i]);
                    }
                }
            }

            var C = xRanged.Ranks.Where(r => r.Count > 1).Sum(xr => xr.Count * (xr.Count - 1)) / 2;
            var D = yRanged.Ranks.Where(r => r.Count > 1).Sum(yr => yr.Count * (yr.Count - 1)) / 2;

            coef = S / Math.Sqrt((0.5 * N * (N - 1) - C) * (0.5 * N * (N - 1) - D));

            return(coef);
        }
Ejemplo n.º 7
0
        public override double GetCoef()
        {
            var xRanged = new RankSelection();

            xRanged.AddSelection(x);

            var yRanged = new RankSelection();

            yRanged.AddSelection(y);

            double coef      = 0;
            double rangedSum = 0;

            for (int i = 0; i < N; i++)
            {
                double xiRank = xRanged.Selection.Where(itm => itm.value == x[i]).First().rank;
                double yiRank = yRanged.Selection.Where(itm => itm.value == y[i]).First().rank;
                rangedSum += (xiRank - yiRank) * (xiRank - yiRank);
            }

            if (xRanged.Ranks.Where(r => r.Items.Count > 1).Count() == 0 &&
                yRanged.Ranks.Where(r => r.Items.Count > 1).Count() == 0)
            {
                coef = 1 - (6 * rangedSum) / (N * (N * N - 1));
            }
            else
            {
                var A = xRanged.Ranks.Where(r => r.Items.Count > 1).Sum(x => x.Count * x.Count * x.Count - x.Count) / 12;
                var B = yRanged.Ranks.Where(r => r.Items.Count > 1).Sum(y => y.Count * y.Count * y.Count - y.Count) / 12;

                double NsExp  = N * (N * N - 1) / 6;
                double top    = NsExp - rangedSum - A - B;
                double bottom = Math.Sqrt((NsExp - 2 * A) * (NsExp - 2 * B));

                coef = top / bottom;
            }

            return(coef);
        }
        public void RankSelection_IgnoreSomeOfPopulation(int chromosomesToIgnore)
        {
            var selection = new RankSelection(1 - chromosomesToIgnore / 4.0);

            AssertLowestChromosomesAreIgnored(selection, chromosomesToIgnore);
        }
Ejemplo n.º 9
0
        static void Main(string[] args)
        {
            Stopwatch stopwatch = new Stopwatch();
            decimal   frequency = Stopwatch.Frequency;

            if (CommandLine.Parser.Default.ParseArguments(args, Options))
            {
                TextWriter reportWriter = Options.OutputFilePath == null ? Console.Out : new StreamWriter(Options.OutputFilePath);

                VerboseLog("Data parsing ...");

                DataParser parser = new DataParser();
                List <KnapsackProblemModel>          knapsackProblemModels        = parser.ParseProblem(Options.InputFiles);
                Dictionary <int, int>                knownResults                 = null;
                Dictionary <int, Tuple <int, long> > bruteForceResults            = new Dictionary <int, Tuple <int, long> >();
                Dictionary <int, Tuple <int, long> > costToRatioHeuristicsResults = new Dictionary <int, Tuple <int, long> >();
                Dictionary <int, Tuple <int, long> > branchAndBoundResults        = new Dictionary <int, Tuple <int, long> >();
                Dictionary <int, Tuple <int, long> > dynamicByCostResults         = new Dictionary <int, Tuple <int, long> >();
                Dictionary <int, Tuple <int, long> > fptasResults                 = new Dictionary <int, Tuple <int, long> >();
                Dictionary <int, Tuple <int, long> > geneticResults               = new Dictionary <int, Tuple <int, long> >();

                if (Options.ResultFiles != null)
                {
                    knownResults = parser.ParseResults(Options.ResultFiles);
                }

                VerboseLog("Done.");

                IKnapsackSolver bruteForceSolver     = new BruteForceSolver();
                IKnapsackSolver ratioHeuristicSolver = new RatioHeuristicSolver();
                IKnapsackSolver branchAndBoundSolver = new BranchAndBoundSolver();
                IKnapsackSolver dynamicByCostSolve   = new DynamicByCostSolver();
                IKnapsackSolver fptasSolver          = null;
                IKnapsackSolver geneticSolver        = null;

                if (Options.FPTAS)
                {
                    fptasSolver = new FPTASSolver(Options.FPTASAccuracy);
                }
                if (Options.Genetics)
                {
                    ISelectionMethod selectionMethod = null;
                    switch (Options.SelectionMethod)
                    {
                    case "roulette": selectionMethod = new RouletteWheelSelection();
                        break;

                    case "rank": selectionMethod = new RankSelection();
                        break;

                    case "elitary": selectionMethod = new EliteSelection();
                        break;

                    default: Console.WriteLine("Wrong selection method for genetics");
                        break;
                    }

                    if (selectionMethod == null)
                    {
                        return;
                    }


                    if (Options.GeneticMetaoptimization)
                    {
                        //Random selection portion
                        for (int i = 0; i < 100; i++)
                        {
                            double randomSelectionPortion = (i * 0.001) + 0;
                            //Crossover rate
                            for (int j = 0; j < 1; j++)
                            {
                                double crossoverRate = (j * 0.03) + 0.22;
                                //Mutation rate
                                for (int k = 0; k < 1; k++)
                                {
                                    double mutationRate = (k * 0.04) + 0.87;

                                    geneticSolver = new GeneticSolver(Options.PopulationSize, Options.IterationsCount, selectionMethod, mutationRate, crossoverRate, randomSelectionPortion, false, false);
                                    geneticResults.Clear();
                                    foreach (KnapsackProblemModel problem in knapsackProblemModels)
                                    {
                                        int result = 0;
                                        try
                                        {
                                            stopwatch.Restart();
                                            result = geneticSolver.Solve(problem);
                                            stopwatch.Stop();
                                        }
                                        catch (Exception ex)
                                        {
                                        }

                                        geneticResults.Add(problem.ProblemId, new Tuple <int, long>(result, stopwatch.ElapsedTicks));
                                    }

                                    decimal totalTime  = 0;
                                    decimal totalError = 0;

                                    foreach (KnapsackProblemModel problem in knapsackProblemModels)
                                    {
                                        int problemId            = problem.ProblemId;
                                        Tuple <int, long> result = geneticResults[problemId];
                                        totalTime  += (result.Item2 / frequency);
                                        totalError += CalculateRelativeError(knownResults[problemId], result.Item1);
                                    }

                                    decimal averageError = totalError / knapsackProblemModels.Count;

                                    reportWriter.WriteLine(randomSelectionPortion + "," + crossoverRate + "," + mutationRate + "," + totalTime + "," + averageError);
                                }
                            }
                        }
                    }

                    geneticSolver = new GeneticSolver(Options.PopulationSize, Options.IterationsCount, selectionMethod, Options.MutationRate, Options.CrossoverRate, Options.RandomSelectionPortion, Options.DiversityCheck, true);
                }

                VerboseLog("Solving JIT instance");
                KnapsackProblemModel jitProblem = new KnapsackProblemModel(-1, 100, new List <Item>
                {
                    new Item(18, 114, 0), new Item(42, 136, 1), new Item(88, 192, 2), new Item(3, 223, 3)
                });

                bruteForceSolver.Solve(jitProblem);
                ratioHeuristicSolver.Solve(jitProblem);
                branchAndBoundSolver.Solve(jitProblem);
                dynamicByCostSolve.Solve(jitProblem);

                if (fptasSolver != null)
                {
                    fptasSolver.Solve(jitProblem);
                }

                if (geneticSolver != null)
                {
                    geneticSolver.Solve(jitProblem);
                }

                VerboseLog("Calculation started");



                foreach (KnapsackProblemModel problem in knapsackProblemModels)
                {
                    VerboseLog("Solving problem:");
                    VerboseLog(problem);

                    int knownResult = -1;
                    if (knownResults != null)
                    {
                        knownResult = knownResults[problem.ProblemId];
                        VerboseLog("Result should be: " + knownResult);
                    }

                    if (Options.BruteForce)
                    {
                        VerboseLog("Brute force solver ...");

                        stopwatch.Restart();
                        int result = bruteForceSolver.Solve(problem);
                        stopwatch.Stop();

                        bruteForceResults.Add(problem.ProblemId, new Tuple <int, long>(result, stopwatch.ElapsedTicks));

                        if (knownResult != -1 && result != knownResult)
                        {
                            Console.WriteLine("ERROR - Brute force algorithm not accurate for problem " + problem);
                            Environment.Exit(1);
                        }
                    }

                    if (Options.BranchAndBound)
                    {
                        VerboseLog("Branch and bound solver ...");

                        stopwatch.Restart();
                        int result = branchAndBoundSolver.Solve(problem);
                        stopwatch.Stop();

                        branchAndBoundResults.Add(problem.ProblemId, new Tuple <int, long>(result, stopwatch.ElapsedTicks));

                        if (knownResult != -1 && result != knownResult)
                        {
                            Console.WriteLine("ERROR - Branch and bound algorithm not accurate for problem " + problem);
                            Environment.Exit(1);
                        }
                    }

                    if (Options.DynamicByCost)
                    {
                        VerboseLog("Dynamic by cost solver ...");

                        stopwatch.Restart();
                        int result = dynamicByCostSolve.Solve(problem);
                        stopwatch.Stop();

                        dynamicByCostResults.Add(problem.ProblemId, new Tuple <int, long>(result, stopwatch.ElapsedTicks));

                        if (knownResult != -1 && result != knownResult)
                        {
                            Console.WriteLine("ERROR - Dynamic by cost algorithm not accurate for problem " + problem);
                            Environment.Exit(1);
                        }
                    }

                    if (Options.CostToRatioHeuristics)
                    {
                        VerboseLog("Ratio heuristics solver ...");

                        stopwatch.Restart();
                        int result = ratioHeuristicSolver.Solve(problem);
                        stopwatch.Stop();

                        costToRatioHeuristicsResults.Add(problem.ProblemId, new Tuple <int, long>(result, stopwatch.ElapsedTicks));
                    }

                    if (Options.FPTAS)
                    {
                        VerboseLog("FPTAS solver ...");

                        if (fptasSolver != null)
                        {
                            stopwatch.Restart();
                            int result = fptasSolver.Solve(problem);
                            stopwatch.Stop();

                            fptasResults.Add(problem.ProblemId, new Tuple <int, long>(result, stopwatch.ElapsedTicks));
                        }
                    }

                    if (Options.Genetics)
                    {
                        VerboseLog("Genetics solver ...");

                        if (geneticSolver != null)
                        {
                            stopwatch.Restart();
                            int result = geneticSolver.Solve(problem);
                            stopwatch.Stop();

                            geneticResults.Add(problem.ProblemId, new Tuple <int, long>(result, stopwatch.ElapsedTicks));
                        }
                    }

                    VerboseLog("Problem solved.");
                }

                reportWriter.Write("Problem ID;Items count");
                if (knownResults != null)
                {
                    reportWriter.Write(";Known result");
                }
                if (Options.BruteForce)
                {
                    reportWriter.Write(";Brute force result;Time [s]");
                    if (knownResults != null)
                    {
                        reportWriter.Write(";Relative error");
                    }
                }
                if (Options.CostToRatioHeuristics)
                {
                    reportWriter.Write(";Cost to weight ration heuristics result;Time [s]");
                    if (knownResults != null)
                    {
                        reportWriter.Write(";Relative error");
                    }
                }
                if (Options.BranchAndBound)
                {
                    reportWriter.Write(";Branch and bound result;Time [s]");
                    if (knownResults != null)
                    {
                        reportWriter.Write(";Relative error");
                    }
                }
                if (Options.DynamicByCost)
                {
                    reportWriter.Write(";Dynamic programming by cost result;Time [s]");
                    if (knownResults != null)
                    {
                        reportWriter.Write(";Relative error");
                    }
                }
                if (Options.FPTAS)
                {
                    reportWriter.Write(";FPTAS result;Time [s]");
                    if (knownResults != null)
                    {
                        reportWriter.Write(";Relative error;Max possible error");
                    }
                }
                if (Options.Genetics)
                {
                    reportWriter.Write(";Genetics result;Time [s]");
                    if (knownResults != null)
                    {
                        reportWriter.Write(";Relative error");
                    }
                }
                reportWriter.WriteLine();

                foreach (KnapsackProblemModel problem in knapsackProblemModels)
                {
                    var problemId = problem.ProblemId;
                    reportWriter.Write(problemId);
                    reportWriter.Write(";" + problem.Items.Count);
                    if (knownResults != null)
                    {
                        reportWriter.Write(";" + knownResults[problemId]);
                    }
                    if (Options.BruteForce)
                    {
                        Tuple <int, long> bruteForceResult = bruteForceResults[problemId];
                        reportWriter.Write(";" + bruteForceResult.Item1 + ";" + bruteForceResult.Item2 / frequency);
                        if (knownResults != null)
                        {
                            reportWriter.Write(";" + CalculateRelativeError(knownResults[problemId], bruteForceResult.Item1));
                        }
                    }
                    if (Options.CostToRatioHeuristics)
                    {
                        Tuple <int, long> heuristicsResult = costToRatioHeuristicsResults[problemId];
                        reportWriter.Write(";" + heuristicsResult.Item1 + ";" + heuristicsResult.Item2 / frequency);
                        if (knownResults != null)
                        {
                            reportWriter.Write(";" + CalculateRelativeError(knownResults[problemId], heuristicsResult.Item1));
                        }
                    }
                    if (Options.BranchAndBound)
                    {
                        Tuple <int, long> heuristicsResult = branchAndBoundResults[problemId];
                        reportWriter.Write(";" + heuristicsResult.Item1 + ";" + heuristicsResult.Item2 / frequency);
                        if (knownResults != null)
                        {
                            reportWriter.Write(";" + CalculateRelativeError(knownResults[problemId], heuristicsResult.Item1));
                        }
                    }
                    if (Options.DynamicByCost)
                    {
                        Tuple <int, long> heuristicsResult = dynamicByCostResults[problemId];
                        reportWriter.Write(";" + heuristicsResult.Item1 + ";" + heuristicsResult.Item2 / frequency);
                        if (knownResults != null)
                        {
                            reportWriter.Write(";" + CalculateRelativeError(knownResults[problemId], heuristicsResult.Item1));
                        }
                    }
                    if (Options.FPTAS)
                    {
                        Tuple <int, long> heuristicsResult = fptasResults[problemId];
                        reportWriter.Write(";" + heuristicsResult.Item1 + ";" + heuristicsResult.Item2 / frequency);
                        if (knownResults != null)
                        {
                            reportWriter.Write(";" + CalculateRelativeError(knownResults[problemId], heuristicsResult.Item1));
                            reportWriter.Write(";" + ((FPTASSolver)fptasSolver).GetMaximumError(problem));
                        }
                    }
                    if (Options.Genetics)
                    {
                        Tuple <int, long> heuristicsResult = geneticResults[problemId];
                        reportWriter.Write(";" + heuristicsResult.Item1 + ";" + heuristicsResult.Item2 / frequency);
                        if (knownResults != null)
                        {
                            reportWriter.Write(";" + CalculateRelativeError(knownResults[problemId], heuristicsResult.Item1));
                        }
                    }
                    reportWriter.WriteLine();
                }

                if (Options.Genetics)
                {
                    decimal totalTime  = 0;
                    decimal totalError = 0;

                    foreach (KnapsackProblemModel problem in knapsackProblemModels)
                    {
                        int problemId            = problem.ProblemId;
                        Tuple <int, long> result = geneticResults[problemId];
                        totalTime  += (result.Item2 / frequency);
                        totalError += CalculateRelativeError(knownResults[problemId], result.Item1);
                    }

                    decimal averageError = totalError / knapsackProblemModels.Count;

                    reportWriter.WriteLine("Aggregate results");
                    reportWriter.WriteLine("Aggregate time");
                    reportWriter.WriteLine(totalTime);
                    reportWriter.WriteLine("Average error");
                    reportWriter.WriteLine(averageError);
                }
            }
            else
            {
                Environment.Exit(1);
            }

            Environment.Exit(0);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Trains and evaluates a genetic algorithm with the specified parameters.
        /// </summary>
        /// <param name="data">The data to be used for training.</param>
        /// <param name="solution">The reference to where the solution will be stored.</param>
        /// <param name="bestChromosome">The best chromosome.</param>
        /// <param name="error">The reference where error rate will be stored.</param>
        /// <param name="predictions">The reference to where the predictions will be stored.</param>
        /// <param name="iterations">The number of iterations to perform.</param>
        /// <param name="population">The size of the population.</param>
        /// <param name="inputCount">The number of inputs.</param>
        /// <param name="shuffle">Value indicating whether to shuffle the chromosomes on each epoch.</param>
        /// <param name="constants">The constant inputs.</param>
        /// <param name="geneType">Type of the gene functions.</param>
        /// <param name="chromosomeType">Type of the chromosome.</param>
        /// <param name="selectionType">Type of the chromosome selection.</param>
        /// <param name="cancelToken">The cancellation token for the async operation.</param>
        /// <param name="progressCallback">The progress callback: current iteration.</param>
        /// <returns>
        ///   <c>true</c> if the training and evaluation was successful, <c>false</c> otherwise.</returns>
        /// <exception cref="ArgumentException">Array should be size of data minus number of inputs.</exception>
        public static bool TrainAndEval(double[] data, ref double[] solution, ref string bestChromosome, ref double error, ref double[] predictions, int iterations, int population, int inputCount, bool shuffle, double[] constants, GeneFunctions geneType, Chromosomes chromosomeType, Selections selectionType, CancellationToken cancelToken, Action <int> progressCallback = null)
        {
            IGPGene gene;

            switch (geneType)
            {
            case GeneFunctions.Simple:
                gene = new SimpleGeneFunction(inputCount + constants.Length);
                break;

            case GeneFunctions.Extended:
                gene = new ExtendedGeneFunction(inputCount + constants.Length);
                break;

            default: return(false);
            }

            IChromosome chromosome;

            switch (chromosomeType)
            {
            case Chromosomes.GPT:
                chromosome = new GPTreeChromosome(gene);
                break;

            case Chromosomes.GEP:
                chromosome = new GEPChromosome(gene, 20);
                break;

            default: return(false);
            }

            ISelectionMethod selection;

            switch (selectionType)
            {
            case Selections.Elite:
                selection = new EliteSelection();
                break;

            case Selections.Rank:
                selection = new RankSelection();
                break;

            case Selections.Roulette:
                selection = new RouletteWheelSelection();
                break;

            default: return(false);
            }

            cancelToken.ThrowIfCancellationRequested();

            var ga = new Population(
                population,
                chromosome,
                new TimeSeriesPredictionFitness(data, inputCount, 0, constants),
                selection
                )
            {
                AutoShuffling = shuffle
            };

            if (solution.Length != data.Length - inputCount)
            {
                throw new ArgumentException("Array should be the size of data minus number of inputs.", nameof(solution));
            }

            var input = new double[inputCount + constants.Length];

            for (var j = 0; j < data.Length - inputCount; j++)
            {
                solution[j] = j + inputCount;
            }

            Array.Copy(constants, 0, input, inputCount, constants.Length);

            for (var i = 0; i < iterations; i++)
            {
                ga.RunEpoch();

                progressCallback?.Invoke(i);

                cancelToken.ThrowIfCancellationRequested();
            }

            error          = 0.0;
            bestChromosome = ga.BestChromosome.ToString();

            for (int j = 0, n = data.Length - inputCount; j < n; j++)
            {
                for (int k = 0, b = j + inputCount - 1; k < inputCount; k++)
                {
                    input[k] = data[b - k];
                }

                solution[j] = PolishExpression.Evaluate(bestChromosome, input);

                error += Math.Abs((solution[j] - data[inputCount + j]) / data[inputCount + j]);

                cancelToken.ThrowIfCancellationRequested();
            }

            error = error / (data.Length - inputCount) * 100;

            if (predictions.Length != 0)
            {
                Array.Copy(solution, solution.Length - inputCount, predictions, 0, inputCount);

                for (var i = inputCount; i < predictions.Length; i++)
                {
                    for (int j = 0; j < inputCount; j++)
                    {
                        input[j] = predictions[(i - inputCount) + j];
                    }

                    predictions[i] = PolishExpression.Evaluate(bestChromosome, input);

                    cancelToken.ThrowIfCancellationRequested();
                }
            }

            return(true);
        }
Ejemplo n.º 11
0
        public void SelectChromosomes_Generation_ChromosomesSelected()
        {
            var target = new RankSelection();
            var c1     = Substitute.ForPartsOf <ChromosomeBase>(2);

            c1.Fitness = 0.1;

            var c2 = Substitute.ForPartsOf <ChromosomeBase>(2);

            c2.Fitness = 0.5;

            var c3 = Substitute.ForPartsOf <ChromosomeBase>(2);

            c3.Fitness = 0;

            var c4 = Substitute.ForPartsOf <ChromosomeBase>(2);

            c4.Fitness = 0.7;

            var generation = new Generation(1, new List <IChromosome>()
            {
                c1, c2, c3, c4
            });

            // Just one selected chromosome is c1.
            FlowAssert.IsAtLeastOneAttemptOk(100, () =>
            {
                var actual = target.SelectChromosomes(2, generation);
                Assert.AreEqual(2, actual.Count);
                Assert.AreEqual(1, actual.Count(c => c.Fitness == 0.1));
            });

            // All selected chromosome is c1.
            FlowAssert.IsAtLeastOneAttemptOk(1000, () =>
            {
                var actual = target.SelectChromosomes(2, generation);
                Assert.AreEqual(2, actual.Count);
                Assert.IsTrue(actual.All(c => c.Fitness == 0.1));
            });

            // Just one selected chromosome is c2.
            FlowAssert.IsAtLeastOneAttemptOk(100, () =>
            {
                var actual = target.SelectChromosomes(2, generation);
                Assert.AreEqual(2, actual.Count);
                Assert.AreEqual(1, actual.Count(c => c.Fitness == 0.5));
            });

            // All selected chromosome is c2.
            FlowAssert.IsAtLeastOneAttemptOk(1000, () =>
            {
                var actual = target.SelectChromosomes(2, generation);
                Assert.AreEqual(2, actual.Count);
                Assert.IsTrue(actual.All(c => c.Fitness == 0.5));
            });

            // Just one selected chromosome is c3.
            FlowAssert.IsAtLeastOneAttemptOk(100, () =>
            {
                var actual = target.SelectChromosomes(2, generation);
                Assert.AreEqual(2, actual.Count);
                Assert.AreEqual(1, actual.Count(c => c.Fitness == 0));
            });

            // All selected chromosome is c3.
            FlowAssert.IsAtLeastOneAttemptOk(1000, () =>
            {
                var actual = target.SelectChromosomes(2, generation);
                Assert.AreEqual(2, actual.Count);
                Assert.IsTrue(actual.All(c => c.Fitness == 0));
            });

            // Just one selected chromosome is c4.
            FlowAssert.IsAtLeastOneAttemptOk(100, () =>
            {
                var actual = target.SelectChromosomes(2, generation);
                Assert.AreEqual(2, actual.Count);
                Assert.AreEqual(1, actual.Count(c => c.Fitness == 0.7));
            });

            // All selected chromosome is c4.
            FlowAssert.IsAtLeastOneAttemptOk(1000, () =>
            {
                var actual = target.SelectChromosomes(2, generation);
                Assert.AreEqual(2, actual.Count);
                Assert.IsTrue(actual.All(c => c.Fitness == 0.7));
            });
        }