string getReportLine(TargetFunctionPoint P)
        {
            if (P == null)
            {
                return("");
            }
            string reportLine = "";

            for (int n = 0; n < P.h.nodes.Count; n++)
            {
                if (P.h.nodes[n].getAttributeValue("variable") == "numerical")
                {
                    reportLine += P.h.nodes[n].getValue().Replace(',', '.') + ";";
                }
            }
            reportLine += P.Q.ToString().Replace(',', '.') + ';';

            return(reportLine);
        }
        void calculateTargetFunction(Hyperparameters h)
        {
            if (poolLoading < pool.Length)
            {
                string reportLine = "";
                for (int i = 0; i < h.nodes.Count; i++)
                {
                    if (h.nodes[i].getAttributeValue("variable") == "numerical")
                    {
                        pool[poolLoading].nodes[i] = h.nodes[i].Clone();
                        reportLine += h.nodes[i].getAttributeValue("value").Replace(',', '.') + ";";
                    }
                }
                form1.log(reportLine);

                poolLoading++;
                if (poolLoading == pool.Length)
                {
                    if (form1.test_count != 0)
                    {
                        test_count = form1.test_count;
                    }
                    double[,] target_functions = new double[pool.Length, test_count];

                    for (int tc = 0; tc < test_count; tc++)
                    {
                        var now2   = new DateTimeOffset(DateTime.Now);
                        var start2 = now2.ToUnixTimeSeconds();

                        List <Algorithm> algorithms = new List <Algorithm>();
                        for (int i = 0; i < pool.Length; i++)
                        {
                            Algorithm alg = Algorithm.newInstance(algorithm);
                            alg.h = pool[i].Clone();
                            algorithms.Add(alg);
                        }

                        List <Thread> trainThreads = new List <Thread>();

                        foreach (Algorithm alg in algorithms)
                        {
                            Thread t = new Thread(new ThreadStart(alg.train));
                            trainThreads.Add(t);
                            t.Start();
                        }

                        foreach (var t in trainThreads)
                        {
                            t.Join();
                        }


                        for (int i = 0; i < pool.Length; i++)
                        {
                            pool[i] = algorithms[i].h.Clone();

                            switch (target_function_type)
                            {
                            case TargetFunctionType.ACCURACY:
                            {
                                target_functions[i, tc] = Convert.ToDouble(pool[i].getValueByName("accuracy").Replace('.', ','));
                                break;
                            }

                            case TargetFunctionType.STDDEV:
                            {
                                target_functions[i, tc] = Convert.ToDouble(pool[i].getValueByName("stdDev").Replace('.', ','));
                                break;
                            }
                            }
                        }
                        form1.log((tc + 1).ToString() + '/' + test_count.ToString() + " test comlete" + TimeSpan.FromSeconds((new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()) - start2).ToString(), Color.LimeGreen);
                    }

                    string[] lines = new string[pool.Length];
                    for (int i = 0; i < pool.Length; i++)
                    {
                        double sum = 0;

                        // AVG
                        for (int j = 0; j < test_count; j++)
                        {
                            sum += target_functions[i, j];
                        }
                        double AVG = sum / test_count;

                        sum = 0;
                        // StdDev
                        for (int j = 0; j < test_count; j++)
                        {
                            sum += (AVG - target_functions[i, j]) * (AVG - target_functions[i, j]);
                        }

                        double StdDev = Math.Sqrt(sum / test_count);

                        // если  target_function равна  (AVG - StdDev), то последующее вычисление критерия оптимальности будет давать результаты ВЫШЕ, чем  target_function
                        pool[i].setValueByName("target_function", (AVG - StdDev).ToString().Replace(',', '.'));
                        pool[i].setValueByName("target_function_AVG", (AVG).ToString().Replace(',', '.'));
                        pool[i].setValueByName("target_function_StdDev", (StdDev).ToString().Replace(',', '.'));

                        double Q = double.Parse(pool[i].getValueByName("target_function").Replace('.', ','));

                        TargetFunctionPoint newPoint = new TargetFunctionPoint(pool[i].Clone(), Q);
                        currentHypercube.Add(newPoint);
                        explored.Add(newPoint);

                        form1.log(newPoint.Q.ToString(), Color.LimeGreen);

                        lines[i] = getReportLine(newPoint);
                    }

                    File.AppendAllLines(report_file_name, lines);

                    poolLoading = 0;
                }
            }
        }
        public void run()
        {
            for (int it = 0; it < 20; it++)
            {
                currentHypercube = new List <TargetFunctionPoint>();

                iteration();

                // поиск максимума
                TargetFunctionPoint maxQ = new TargetFunctionPoint(null, 0);

                for (int i = 0; i < currentHypercube.Count; i++)
                {
                    variablesVisualizer.addPoint(currentHypercube[i].Q, " [" + i.ToString() + "]");

                    if (maxQ.Q < currentHypercube[i].Q)
                    {
                        maxQ = currentHypercube[i];
                    }
                }

                variablesVisualizer.addPoint(maxQ.Q, "max Q");

                form1.log(getReportLine(maxQ), Color.Magenta);

                bool isOptimumInCenter = true;

                for (int i = 0; i < P.nodes.Count; i++)
                {
                    if (P.nodes[i].getAttributeValue("variable") == "numerical")
                    {
                        string maxQVariableValue = maxQ.h.nodes[i].getValue();
                        string variableCenter    = getVariableCenter(P.nodes[i]);
                        if (maxQVariableValue != variableCenter)
                        {
                            isOptimumInCenter = false;
                        }
                    }
                }


                if (isOptimumInCenter)
                {
                    //если максимум в центре - сжатие
                    form1.log("Сжатие", Color.Cyan);
                    variablesVisualizer.markLast("Сжатие", "max Q");
                    for (int i = 0; i < P.nodes.Count; i++)
                    {
                        if (P.nodes[i].getAttributeValue("variable") == "numerical")
                        {
                            string newMin = "";
                            string newMax = "";
                            if (P.nodes[i].getAttributeValue("max").Contains('.') || P.nodes[i].getAttributeValue("max").Contains(','))
                            {
                                double min_double = double.Parse(P.nodes[i].getAttributeValue("min").Replace('.', ','));
                                double max_double = double.Parse(P.nodes[i].getAttributeValue("max").Replace('.', ','));
                                // сужение интервала
                                if (min_double + ((max_double - min_double) / 4) > 0)
                                {
                                    newMin = (min_double + ((max_double - min_double) / 4)).ToString().Replace(',', '.');
                                }
                                else
                                {
                                    newMin = min_double.ToString().Replace(',', '.');
                                }
                                newMax = (max_double - ((max_double - min_double) / 4)).ToString().Replace(',', '.');
                            }
                            else
                            {
                                int min_int = int.Parse(P.nodes[i].getAttributeValue("min"));
                                int max_int = int.Parse(P.nodes[i].getAttributeValue("max"));
                                // сужение интервала
                                if (min_int + ((max_int - min_int) / 4) >= 2)
                                {
                                    newMin = (min_int + ((max_int - min_int) / 4)).ToString();
                                }
                                else
                                {
                                    newMin = min_int.ToString();
                                }
                                newMax = (max_int - ((max_int - min_int) / 4)).ToString();
                            }
                            P.nodes[i].setAttribute("min", newMin);
                            P.nodes[i].setAttribute("max", newMax);
                        }
                    }
                }
                else
                {
                    //иначе - перемещение центра в точку максимума
                    form1.log("Перемещение из " + getReportLine(lastP) + " в " + getReportLine(maxQ), Color.Cyan);
                    variablesVisualizer.markLast("Перемещение", "max Q");
                    for (int i = 0; i < P.nodes.Count; i++)
                    {
                        if (P.nodes[i].getAttributeValue("variable") == "numerical")
                        {
                            string newMin = "";
                            string newMax = "";
                            if (P.nodes[i].getAttributeValue("max").Contains('.') || P.nodes[i].getAttributeValue("max").Contains(','))
                            {
                                double min_double = double.Parse(P.nodes[i].getAttributeValue("min").Replace('.', ','));
                                double max_double = double.Parse(P.nodes[i].getAttributeValue("max").Replace('.', ','));
                                double value      = double.Parse(maxQ.h.nodes[i].getValue().Replace('.', ','));
                                // перемещение центра
                                if ((value - ((max_double - min_double) / 2)) > 0)
                                {
                                    newMin = (value - ((max_double - min_double) / 2)).ToString().Replace(',', '.');
                                }
                                else
                                {
                                    newMin = min_double.ToString().Replace(',', '.');
                                }
                                newMax = (value + ((max_double - min_double) / 2)).ToString().Replace(',', '.');
                            }
                            else
                            {
                                int min_int = int.Parse(P.nodes[i].getAttributeValue("min"));
                                int max_int = int.Parse(P.nodes[i].getAttributeValue("max"));
                                int value   = int.Parse(maxQ.h.nodes[i].getValue());
                                // перемещение центра
                                if (value - ((max_int - min_int) / 2) >= 2)
                                {
                                    newMin = (value - ((max_int - min_int) / 2)).ToString();
                                }
                                else
                                {
                                    newMin = min_int.ToString();
                                }
                                newMax = (value + ((max_int - min_int) / 2)).ToString();
                            }
                            P.nodes[i].setAttribute("min", newMin);
                            P.nodes[i].setAttribute("max", newMax);
                        }
                    }
                }
                lastP = maxQ;

                variablesVisualizer.refresh();
            }
        }