public static Point2D FindMinimum(Func <double, double, double> f, Point2D b1, Point2D h, double eps0) { Point2D b2, xk, x; bool flag; double z = 0.1; double f1, f2; Logger.Write("===> Минимизация методом Хука-Дживса <=="); Logger.WriteContinue(" |Начальная точка b1: {0}", b1); Logger.WriteContinue(" |Шаг h: {0} ", h); Logger.WriteContinue(" |Точность eps: {0} ", eps0); do { do { xk = b1; //Исследуюший поиск b2 = search(f, xk, h); Logger.Write("1. xk = b1 = {0}", xk); Logger.Write("2. Выполняем исследующий поиск вокруг точки xk: b2 = {0}", b2); do { //Шаг по образцу xk = new Point2D(b1.X + 2 * (b2.X - b1.X), b1.Y + 2 * (b2.Y - b1.Y)); Logger.Write("3. Выполняем шаг по образцу xk = b1 + 2(b2-b1) = {0}", xk); //Исследующий поиск x = search(f, xk, h); Logger.Write("4. Выполняем исследующий поиск вокруг точки xk: x = {0}", x); b1 = b2; Logger.Write("5. b1 = b2 = {0}", b1); f1 = f(x.X, x.Y); f2 = f(b1.X, b1.Y); Logger.Write("6. f(x) = {0}; f(b1) = {1}", f1, f2); if (f1 < f2) { b2 = x; Logger.WriteContinue(" f(x) < f(b1) => переход на шаг 3"); } } while (f1 < f2); flag = f(x.X, x.Y) > f(b1.X, b1.Y); if (flag) { Logger.Write("f(x) > f(b1) => переход на шаг 1"); } } while (flag); if (OptimizationUtils.EuclidNorm(h) <= eps0) { break; } //Уменьшаем шаг h.X = z * h.X; h.Y = z * h.Y; Logger.Write("9. Уменьшаем шаг: h = {0} * h = {1}", z, h); } while (true); Logger.Write("||h|| = {0} <= eps => поиск завершен"); Logger.WriteContinue("Минимум найден: b1 = {0}", b1); return(b1); }
/// <summary> /// Осуществляет оптимизацию многомерной функции методом Гаусса-Зейделя /// </summary> /// <param name="f">Минимизируемая функция</param> /// <param name="x0">начальной точки посика</param> /// <param name="interval">интервалы поиска</param> /// <param name="h">Векор положительных приращений координат</param> /// <param name="eps0">Точность</param> /// <returns></returns> public static Point2D FindMinimum(Func <double, double, double> f, Point2D x0, Point2D h, double eps0) { /*Стоило бы сделать поддержку функций многих переменных (N>2), но тут трудности в преобразовании * Func<double[], double> -> Func<double, double>*/ double finder_h = 0.05; //Шаг поиска отрезка минимума double z = 0.1; //Уменьшение шага поиска double equal_eps = eps0; //Совпадение Point2D x = new Point2D(0, 0); Func <double, double> f_fixed; Interval interval; double ak; Logger.Write("===> Минимизация методом Гаусса-Зейделя <=="); Logger.WriteContinue(" |Начальная точка x0: {0}", x0); Logger.WriteContinue(" |Шаг h: {0} ", h); Logger.WriteContinue(" |Точность eps: {0} ", eps0); string format = OptimizationUtils.GetFormat(eps0 / 10); do { do { x0.X = x.X; x0.Y = x.Y; Logger.Write("Минимазация по каждой координате"); //Поочередная минимизация по каждой координате //X Logger.WriteContinue("X:"); f_fixed = a => f(x0.X + a * h.X, x0.Y); interval = IntervalFinder.Find(x0.X, finder_h, f_fixed); ak = GoldenRatioMethod.FindMinimum(interval, f_fixed, eps0 / 5); x.X = x0.X + ak * h.X; Logger.WriteContinue(" 3. ak = {0:" + format + "}", ak); Logger.WriteContinue(" 4. x[k+1].X=x[k].X + ak*h.X = {0:" + format + "} + {1:" + format + "} * {2:" + format + "} = {3:" + format + "}", x0.X, ak, h.X, x.X); //Y Logger.WriteContinue("Y"); f_fixed = a => f(x.X, x0.Y + a * h.Y); interval = IntervalFinder.Find(x0.Y, finder_h, f_fixed); ak = GoldenRatioMethod.FindMinimum(interval, f_fixed, eps0 / 5); x.Y = x0.Y + ak * h.Y; Logger.WriteContinue(" 3. ak = {0:" + format + "}", ak); Logger.WriteContinue(" 4. x[k+1].Y=x[k].Y + ak*h.Y = {0:" + format + "} + {1:" + format + "} * {2:" + format + "} = {3:" + format + "}", x0.Y, ak, h.Y, x.Y); }while (!check_equal(x0, x, equal_eps)); Logger.Write("x[k+1]==x[k]"); var h0 = h; if (OptimizationUtils.EuclidNorm(h) <= eps0) { break; } //Уменьшаем шаг h.X = z * h.X; h.Y = z * h.Y; Logger.WriteContinue("9. Уменьшаем шаг: h = {0:" + format + "} * {1:" + format + "} = {2:" + format + "}", z, h0, h); Logger.WriteContinue("Переход на шаг 3"); } while (true); Logger.Write("||h|| = {0:" + format + "} < eps", OptimizationUtils.EuclidNorm(h)); Logger.Write("Минимум найден: {0:" + format + "}", x); return(x); }