// Measure FPTAS time, average and max error
        static (List <FPTASSummary>, string instanceResult) RunFPTAS(Dataset dataset, double[] errors)
        {
            Console.WriteLine("{0}: starting calculating dateset {1}", DateTime.Now, dataset.GetFilePath());

            var csvBuilder = new StringBuilder();

            csvBuilder.AppendLine(TestResultHelper.GetFPTASHeader());

            List <FPTASResult> instacesResults = new List <FPTASResult>();

            for (int i = 1; i <= dataset.LastInstanceId; i++)
            {
                Console.WriteLine($"{DateTime.Now}::{dataset.Name}::{dataset.InstanceItemsCount}::{i}");

                // Load instance
                var instance = InstanceLoader.LoadInstanceAsync(dataset, i);

                if (instance == null)
                {
                    continue;
                }

                // Load optimal soultion
                int optimalResult = InstanceLoader.LoadSolution(dataset, i);

                foreach (var err in errors)
                {
                    instacesResults.Add(RunFPAS(instance, optimalResult, csvBuilder, err));
                }
            }

            var summaryItems = new List <FPTASSummary>();

            foreach (var err in errors)
            {
                summaryItems.Add(GetSummaryItem(dataset, instacesResults, err));
            }

            return(summaryItems, csvBuilder.ToString());
        }
        // Measure algorithms time
        private static TestResult RunAlgorithms(Dataset dataSet, int measurementCount)
        {
            Console.WriteLine("{0}: starting calculating dateset {1}", DateTime.Now, dataSet.GetFilePath());

            var csvBuilder = new StringBuilder();

            csvBuilder.AppendLine(TestResultHelper.GetInstanceResultHeader());

            var stopwatch = new Stopwatch();

            double BFTotal    = 0;
            double BandBTotal = 0;
            double dpTotal    = 0;

            double reduxTotal  = 0;
            double reduxErrSum = 0;
            double reduxMaxErr = 0;

            double greedyTotal  = 0;
            double greedyErrSum = 0;
            double greedyMaxErr = 0;

            double ftpasTotal = 0;

            for (int i = 1; i <= dataSet.LastInstanceId; i++)
            {
                Console.WriteLine($"{DateTime.Now}::{dataSet.Name}::{dataSet.InstanceItemsCount}::{i}");

                // Load instance and solution
                var instance = InstanceLoader.LoadInstanceAsync(dataSet, i);
                if (instance == null)
                {
                    continue;
                }

                int optimalResult = InstanceLoader.LoadSolution(dataSet, i);

                double bruteForceTimeAvg     = 0;
                double branchAndBoundTimeAvg = 0;
                double dynamicProgrammingAvg = 0;
                double greedyAvg             = 0;
                double reduxAvg = 0;

                int[] greedyHeuristicResult = null;
                int[] reduxHeuristicResult  = null;
                for (int j = 0; j < measurementCount; j++)
                {
                    stopwatch.Reset();

                    // Start Brute Force
                    stopwatch.Start();
                    var bruteForceResult = BruteForce.Solve(0, instance.Weights, instance.Prices, 0, 0, instance.MaxWeight, instance.MinPrice, new int[instance.N + 1], new int[instance.N + 1]);
                    stopwatch.Stop();

                    CheckResult(instance, bruteForceResult[instance.N], optimalResult, dataSet.Name, nameof(BruteForce));
                    bruteForceTimeAvg += stopwatch.Elapsed.TotalMilliseconds;

                    stopwatch.Reset();

                    // Start Branch and Bound
                    stopwatch.Start();
                    var branchAndBoundResult = BranchAndBound.Solve(0, instance.Weights, instance.Prices, 0, 0, instance.MaxWeight, new int[instance.N + 1], new int[instance.N + 1]);
                    //BranchAndBound.Decide(0, instance.Weights, instance.Prices, 0, 0, instance.MaxWeight, 324);
                    stopwatch.Stop();

                    CheckResult(instance, branchAndBoundResult[instance.N], optimalResult, dataSet.Name, nameof(BranchAndBound));
                    branchAndBoundTimeAvg += stopwatch.Elapsed.TotalMilliseconds;

                    stopwatch.Reset();

                    // Start Dynamic programming
                    stopwatch.Start();
                    var dynamicProgrammingResult = DynamicProgramming.Solve(instance.Items, instance.MaxWeight);
                    stopwatch.Stop();

                    CheckResult(instance, dynamicProgrammingResult[instance.N], optimalResult, dataSet.Name, nameof(DynamicProgramming));
                    dynamicProgrammingAvg += stopwatch.Elapsed.TotalMilliseconds;

                    stopwatch.Reset();

                    // Start Greedy heuristic
                    stopwatch.Start();
                    greedyHeuristicResult = GreedyHeuristic.Solve(instance.Items.ToList(), instance.MaxWeight);
                    stopwatch.Stop();

                    //CheckResult(instance, greedyHeuristicResult[instance.N], optimalPrice, dataSet.Name, nameof(GreedyHeuristic));
                    greedyAvg += stopwatch.Elapsed.TotalMilliseconds;

                    stopwatch.Reset();

                    // Start Redux heuristic
                    stopwatch.Start();
                    reduxHeuristicResult = ReduxHeuristic.Solve(instance.Items.ToList(), instance.MaxWeight);
                    stopwatch.Stop();

                    reduxAvg += stopwatch.Elapsed.TotalMilliseconds;

                    stopwatch.Reset();
                }

                BFTotal     += Avg(bruteForceTimeAvg, measurementCount);
                BandBTotal  += Avg(branchAndBoundTimeAvg, measurementCount);
                dpTotal     += Avg(dynamicProgrammingAvg, measurementCount);
                greedyTotal += Avg(greedyAvg, measurementCount);
                reduxTotal  += Avg(reduxAvg, measurementCount);

                csvBuilder.AppendLine(TestResultHelper.FormatInstanceResultRow(
                                          instance.Id,
                                          instance.N,
                                          Avg(bruteForceTimeAvg, measurementCount),
                                          Avg(branchAndBoundTimeAvg, measurementCount),
                                          Avg(dynamicProgrammingAvg, measurementCount),
                                          Avg(greedyAvg, measurementCount),
                                          Avg(reduxAvg, measurementCount),
                                          0
                                          ));
            }

            Console.WriteLine("{0}: calculating dataset {1} ended", DateTime.Now, dataSet.GetFilePath());

            return(new TestResult
            {
                InstanceSize = dataSet.InstanceItemsCount,
                InstancesResults = csvBuilder.ToString(),
                BFTime = Avg(BFTotal, dataSet.InstancesCount),
                BandBTime = Avg(BandBTotal, dataSet.InstancesCount),
                GreedyHeuristicTime = Avg(greedyTotal, dataSet.InstancesCount),
                ReduxHeuristicTime = Avg(reduxTotal, dataSet.InstancesCount),
                DPTime = Avg(dpTotal, dataSet.InstancesCount),
                FTPASTime = Avg(ftpasTotal, dataSet.InstancesCount),

                GreedyRelErr = Avg(greedyErrSum, dataSet.InstancesCount),
                GreedyMaxErr = greedyMaxErr,
                ReduxRelErr = Avg(reduxErrSum, dataSet.InstancesCount),
                ReduxMaxErr = reduxMaxErr
            });
        }