public vec2 getMin(Func <vec2, double> f, vec2[] range, double eps)
        {
            Random rand    = new Random();
            var    rnd_pts = new vec2[] { getRndPoint(rand, range), getRndPoint(rand, range), getRndPoint(rand, range) };


            var points = rnd_pts;

            while (true)
            {
                var sorted_pts = sortPoints(points, f);
                var x_h        = sorted_pts[0]; //highest
                var x_g        = sorted_pts[1]; // middle
                var x_l        = sorted_pts[2]; // lowest

                var f_h = f(x_h);
                var f_g = f(x_g);
                var f_l = f(x_l);

                LogBoth(String.Format("high: f({0}, {1}) = {2} ", x_h.x, x_h.y, f_h));
                LogBoth(String.Format("middle: f({0}, {1}) = {2} ", x_g.x, x_g.y, f_g));
                LogBoth(String.Format("low: f({0}, {1}) = {2} \n\n", x_l.x, x_l.y, f_l));

                var x_c = new vec2( // center
                    (x_g.x + x_l.x) / 2,
                    (x_g.y + x_l.y) / 2
                    );


                var x_r = new vec2( // reflected
                    (1 + alpha) * x_c.x - alpha * x_h.x,
                    (1 + alpha) * x_c.y - alpha * x_h.y
                    );

                var f_r = f(x_r);

                if (f_r < f_l)
                {
                    // отраженная точка меньше минимальной
                    // направление удачное, пробуем растянуть симплекс
                    var x_e = new vec2( // extension
                        (1 - beta) * x_c.x + beta * x_r.x,
                        (1 - beta) * x_c.y + beta * x_r.y
                        );

                    var f_e = f(x_e);

                    if (f_e < f_r)
                    {
                        // растягиваем
                        x_h = x_e;
                        LogBoth(String.Format("Растяжение"));
                    }
                    else
                    {
                        // переместились слишком далеко
                        x_h = x_r;
                        LogBoth(String.Format("Too far"));
                    }
                }
                else if (f_r > f_l && f_r < f_g)
                {
                    // отраженная точка между минимальной и средней
                    // выбор точки неплохой (новая лучше двух прежних f_g и f_h)
                    x_h = x_r;
                }
                else if (f_r > f_g)
                {
                    if (f_r < f_h)
                    {
                        // отраженная точка между средней и максимальной
                        // меняем местами x_r с x_h и f_r с f_h
                        var tmp_x = x_r;
                        x_r = x_h; x_h = tmp_x;
                        var tmp_f = f_r;
                        f_r = f_h; f_h = tmp_f;
                    }
                    else
                    {
                        // отраженная точка хуже некуда
                    }

                    // производим сжатие
                    var x_s = new vec2( // squeeze
                        gamma * x_h.x + (1 - gamma) * x_c.x,
                        gamma * x_h.y + (1 - gamma) * x_c.y
                        );

                    var f_s = f(x_s);
                    LogBoth(String.Format("Сжатие"));

                    if (f_s < f_h)
                    {
                        x_h = x_s;
                    }
                    else
                    {
                        // первоначальные точки оказались самыми удачными
                        // делаем глобальное сжатие симплекса

                        LogBoth(String.Format("Глобальное сжатие"));
                        x_g.x = x_l.x + (x_g.x - x_l.x) / 2;
                        x_g.y = x_l.y + (x_g.y - x_l.y) / 2;

                        x_h.x = x_l.x + (x_h.x - x_l.x) / 2;
                        x_h.y = x_l.y + (x_h.y - x_l.y) / 2;
                    }
                }

                // условие выхода
                var prx = Math.Sqrt(
                    (Math.Pow(f(x_l) - f(x_h), 2)
                     + Math.Pow(f(x_g) - f(x_h), 2)
                     + Math.Pow(f(x_l) - f(x_g), 2)) / 3
                    );

                if (prx < eps)
                {
                    return(x_l);
                }

                points = new vec2[] { x_h, x_g, x_l };
            }
        }
 public static double f1(vec2 v)
 {
     return(100 * Math.Pow(v.y - v.x * v.x, 2) + 5 * Math.Pow(1 - v.x, 2));
 }
 public static double f2(vec2 v)
 {
     return(Math.Pow(v.x * v.x + v.y - 11, 2) + Math.Pow(v.x + v.y * v.y - 7, 2));
 }
        static void Main(string[] args)
        {
            txtMirror = new StreamWriter("output.txt");

            var inst = new Program();

            bool flag = true;

            while (flag)
            {
                double from_x, from_y, to_x, to_y, eps;

                LogBoth("Input from_x: ");
                if (!double.TryParse(Console.ReadLine(), out from_x))
                {
                    Console.WriteLine("Wrong input");
                    continue;
                }
                else
                {
                    LogFile(from_x.ToString());
                }

                LogBoth("Input from_y: ");
                if (!double.TryParse(Console.ReadLine(), out from_y))
                {
                    Console.WriteLine("Wrong input");
                    continue;
                }
                else
                {
                    LogFile(from_y.ToString());
                }

                LogBoth("Input to_x: ");
                if (!double.TryParse(Console.ReadLine(), out to_x))
                {
                    Console.WriteLine("Wrong input");
                    continue;
                }
                else
                {
                    LogFile(to_x.ToString());
                }

                LogBoth("Input to_y: ");
                if (!double.TryParse(Console.ReadLine(), out to_y))
                {
                    Console.WriteLine("Wrong input");
                    continue;
                }
                else
                {
                    LogFile(to_y.ToString());
                }

                LogBoth("Input eps: ");
                if (!double.TryParse(Console.ReadLine(), out eps))
                {
                    Console.WriteLine("Wrong input");
                    continue;
                }
                else
                {
                    LogFile(eps.ToString());
                }

                var range = new vec2[] { new vec2(from_x, from_y), new vec2(to_x, to_y) };


                LogBoth("START Rosenbrock");
                var rsnbrck_min = inst.getMin(f1, range, eps);
                LogBoth(String.Format("Found Rosenbrock min: f({0}, {1}) = {2}", rsnbrck_min.x, rsnbrck_min.y, f1(rsnbrck_min)));

                LogBoth("START Himmelblau");
                var hmmlbl_min = inst.getMin(f2, range, eps);
                LogBoth(String.Format("Found Himmelblau min: f({0}, {1}) = {2}", hmmlbl_min.x, hmmlbl_min.y, f2(hmmlbl_min)));

                LogBoth("\n\n\nRESULTS:");
                LogBoth(String.Format("Found Rosenbrock min: f({0}, {1}) = {2}", rsnbrck_min.x, rsnbrck_min.y, f1(rsnbrck_min)));
                LogBoth(String.Format("Found Himmelblau min: f({0}, {1}) = {2}", hmmlbl_min.x, hmmlbl_min.y, f2(hmmlbl_min)));


                txtMirror.Flush();

                Console.WriteLine("File output created 'output.txt'.\nPress to try again. Esc - exit");
                if (Console.ReadKey().KeyChar == 27)
                {
                    break;
                }
            }
        }