/// <summary> /// Минимизация функции /// </summary> /// <param name="f">Функция</param> /// <param name="x">Начальное приближение</param> /// <param name="gradient_calc">Функция вычисление градиента</param> /// <param name="eps">Точность</param> /// <param name="steps_count">Возвращаемое значение: число шагов, за которое был найден ответ</param> /// <returns></returns> override public Vector <double> FindMinimum(Func <Vector <double>, double> f, Vector <double> x, AbstractGradientCalc gradient_calc, double eps, out int steps_count) { ///!!!!!!!!! double interval_h = 0.0001; //Шаг для поиска интервала double min_eps = 0.0001; //Точность для поиска минимума steps_count = 0; //Число шагов string format = Utils.GetFormat(eps); double norm; //Создаем единичную квазиньютновскую матрицу Matrix <double> H = Matrix <double> .Build.DenseIdentity(x.Count, x.Count); //Matrix<double> H_prev = null; Vector <double> p = Vector <double> .Build.Dense(x.Count); Vector <double> grad = null; Vector <double> grad_prev = Vector <double> .Build.Dense(x.Count); Vector <double> x_prev = Vector <double> .Build.Dense(x.Count); Logger.Write("===> Минимизация методом переменной метрики <=="); Logger.WriteContinue(" |Начальная точка x0: {0}", x.Vector2String(format)); Logger.WriteContinue(" |Точность eps: {0} ", eps.ToString(format)); Logger.Write("Шаг 1: k=0"); //Вычисление градиента grad = gradient_calc.CalcGradient(f, x); while ((norm = calc_norm(grad)) > eps) { Logger.Write("Шаг 2: Вычисление градиента"); Logger.WriteContinue("grad = {0}", grad.Vector2String(format)); Logger.Write("Шаг 3: Проверка критерия останова:"); Logger.WriteContinue("Норма norm = {0}", norm.ToString(format)); Logger.WriteContinue("norm > eps : {0} > {1}", norm.ToString(format), eps.ToString(format)); if (steps_count > 0) { //Вспомогательные матрицы (Матрицы столбцы) var s_v = (x - x_prev); var s = s_v.ToColumnMatrix(); Logger.Write("Шаг 5: s:{0}T", s_v.Vector2String(format)); var y_v = (grad - grad_prev); var y = y_v.ToColumnMatrix(); Logger.Write("Шаг 6: y:{0}T", y_v.Vector2String(format)); //Эти же транспонированные var y_t = y.Transpose(); var s_t = s.Transpose(); //Пересчет квазиньютоновской матрицы H = H - (H * y * y_t * H) / (y_t * H * y)[0, 0] + (s * s_t) / (y_t * s)[0, 0]; Logger.Write("Шаг 7: Пересчет матрицы H:\n{0}", H); } //Вычисление направления поиска p = -H * grad; Logger.Write("Шаг 8: Направление поиска p = {0}", p.Vector2String(format)); //Определяем шаг поиска методом одномерной оптимизации Func <double, double> f_ = y => f(x + y * p); var interval = IntervalFinder.Find(0, interval_h, f_); var a = GoldenRatioMethod.FindMinimum(interval, f_, min_eps); Logger.Write("Шаг 9: Определение длины шага"); Logger.WriteContinue("ak = {0}", a); x.CopyTo(x_prev); x = x + a * p; Logger.Write("Шаг 10: x = {0}", x.Vector2String(format)); //Вычисление градиента grad.CopyTo(grad_prev); grad = gradient_calc.CalcGradient(f, x); steps_count++; Logger.Write("Шаг 11: k = k +1 = {0}", steps_count); Logger.Write("----------------------"); } Logger.Write("Шаг 3: Проверка критерия останова:"); Logger.WriteContinue("Норма norm = {0}", norm.ToString(format)); Logger.WriteContinue("norm > eps : {0} > {1}", norm.ToString(format), eps.ToString(format)); Logger.Write("Шаг 12: x* = x = {0}", x.Vector2String(format)); Logger.WriteContinue("Поиск закончен"); Logger.WriteContinue("Число итераций: {0}", steps_count); return(x); }
/// <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); }
/// <summary> /// Минимизация функции /// </summary> /// <param name="f">Функция</param> /// <param name="x">Начальное приближение</param> /// <param name="gradient_calc">Функция вычисление градиента</param> /// <param name="eps">Точность</param> /// <param name="steps_count">Возвращаемое значение: число шагов, за которое был найден ответ</param> /// <returns></returns> override public Vector <double> FindMinimum(Func <Vector <double>, double> f, Vector <double> x, AbstractGradientCalc gradient_calc, double eps, out int steps_count) { Vector <double> grad = null; ///!!!!!!!!! double interval_h = 0.000001; //Шаг для поиска интервала double min_eps = 0.000001; //Точность для поиска минимума string format = Utils.GetFormat(eps / 100); //Форматная строка для вывода чисел с нужным числом знаков steps_count = 0; double norm = 0; Logger.Write("===> Минимизация оптимальным градиентным методом <=="); Logger.WriteContinue(" |Начальная точка x0: {0}", x.Vector2String(format)); Logger.WriteContinue(" |Точность eps: {0} ", eps.ToString(format)); Logger.Write("Шаг 1: k = {0}", steps_count); //Вычисление градиента grad = gradient_calc.CalcGradient(f, x); while ((norm = calc_norm(grad)) > eps) { Debug.WriteLine("Grad: {0} f**k", "kek"); Logger.Write("Шаг 2: Вычисление градиента"); Logger.WriteContinue("grad = {0}", grad.Vector2String(format)); Logger.Write("Шаг 3: Проверка критерия останова:"); Logger.WriteContinue("Норма norm = {0}", norm.ToString(format)); Logger.WriteContinue("norm > eps : {0} > {1}", norm.ToString(format), eps.ToString(format)); //Вычисление длины шага //ak = arg min f(x-a*gradf(x)); Func <double, double> f_ = y => f(x - y * grad); var interval = IntervalFinder.Find(0, interval_h, f_); var a = GoldenRatioMethod.FindMinimum(interval, f_, min_eps); Logger.Write("Шаг 4: Определение длины шага"); Logger.WriteContinue("ak = {0}", a.ToString(format)); //Шаг x = x - a * grad; //Debug.WriteLine("x: {0}", x.Vector2String("N3")); Logger.Write("Шаг 5: Xk+1 = Xk + a*grad = {0}", x.Vector2String(format)); grad = gradient_calc.CalcGradient(f, x); steps_count++; Logger.Write("Шаг 6: k = k +1 = {0}", steps_count); Logger.Write("----------------------"); } Logger.Write("Шаг 3: Проверка критерия останова:"); Logger.WriteContinue("Норма norm = {0}", norm.ToString(format)); Logger.WriteContinue("norm > eps : {0} > {1}", norm.ToString(format), eps.ToString(format)); Logger.Write("Шаг 8: x* = x = {0}", x.Vector2String(format)); Logger.WriteContinue("Поиск закончен"); Logger.WriteContinue("Число итераций: {0}", steps_count); return(x); }
/// <summary> /// Минимизация функции /// </summary> /// <param name="f">Функция</param> /// <param name="x">Начальное приближение</param> /// <param name="gradient_calc">Функция вычисление градиента</param> /// <param name="eps">Точность</param> /// <param name="steps_count">Возвращаемое значение: число шагов, за которое был найден ответ</param> /// <returns></returns> public Vector <double> FindMinimum(Func <Vector <double>, double> f, Vector <double> x, AbstractGradientCalc gradient_calc, double eps, out int steps_count, Func <Vector <double>, double>[] borders) { ///!!!!!!!!! double interval_h = eps; //Шаг для поиска интервала double min_eps = eps; //Точность для поиска минимума steps_count = 0; //Число шагов string format = Utils.GetFormat(eps); double norm; //Создаем единичную квазиньютновскую матрицу Matrix <double> H = Matrix <double> .Build.DenseIdentity(x.Count, x.Count); //Matrix<double> H_prev = null; Vector <double> p = Vector <double> .Build.Dense(x.Count); Vector <double> grad = null; Vector <double> grad_prev = Vector <double> .Build.Dense(x.Count); Vector <double> x_prev = Vector <double> .Build.Dense(x.Count); //Вычисление градиента grad = gradient_calc.CalcGradient(f, x); while (((norm = Utils.CalcNorm(grad)) > eps) && (steps_count < 3000)) { if (steps_count > 0) { //Вспомогательные матрицы (Матрицы столбцы) var s_v = (x - x_prev); var s = s_v.ToColumnMatrix(); var y_v = (grad - grad_prev); var y = y_v.ToColumnMatrix(); //Эти же транспонированные var y_t = y.Transpose(); var s_t = s.Transpose(); //Пересчет квазиньютоновской матрицы H = H - (H * y * y_t * H) / (y_t * H * y)[0, 0] + (s * s_t) / (y_t * s)[0, 0]; } //Вычисление направления поиска p = -H * grad; //Определяем шаг поиска методом одномерной оптимизации Func <double, double> f_ = y => f(x + y * p); var interval = IntervalFinder.Find(0, interval_h, f_); var a = GoldenRatioMethod.FindMinimum(interval, f_, min_eps); x.CopyTo(x_prev); x = x + a * p; //WTF //if (!Utils.CheckInD0(x, borders)) return x; //Вычисление градиента grad.CopyTo(grad_prev); grad = gradient_calc.CalcGradient(f, x); steps_count++; } return(x); }