Текст подпрограммы и версий
mnr6r_c.zip , mnr6d_c.zip
Тексты тестовых примеров
tmnr6r_c.zip , tmnr6d_c.zip

Подпрограмма:  mnr6r_c

Назначение

Решение задачи минимизации дифференцируемой функции многих переменных при наличии двусторонних ограничений на переменные методом Дэвидона - Флетчера - Пауэлла.

Математическое описание

Для решения задачи

                 min  f (x) ,
                 xQ 
    Q = { x:  x  En ,   aj ≤ xj ≤ bj ,   aj > - ∞,   bj < ∞ ,   j = 1, 2, ..., n } , 

используется модификация метода Дэвидона - Флетчера - Пауэлла. Вычисленная точка  xk  Q, где  k - номер итерации, считается точкой минимума, если выполнено хотя бы одно из следующих условий:

1.  | xjk - xjk - 1 | ≤ XE(J) для всех  j = 1, 2, ..., n, где  xk = (x1k, x2k,..., xnk ) - точка вычисленная на  k - й итерации, а XE - заданный вектор точности решения по аргументу;
2.  | f (xm ) - f (xm - 1) | ≤ FE для всех  m = k, k - 1, k - 2, где  xm - точка, вычисленная на  m - й итерации, а FE - заданная точность решения задачи по функции;
3.  | f 'j (xk ) | ≤ GE (J) для всех  j = 1, 2, ..., n, где  f 'j (xk ) -  j - я компонента градиента функции  f (x) в точке  xk, а GE - заданный вектор точности решения по градиенту;
4.  выполнено заданное число итераций;
5.  истекло заданное время счета;
6.  произошло замедление счета (см. замечания по использованию).

При одномерной минимизации функции вдоль направления спуска используется метод деления заданного отрезка на константу, которая является параметром алгоритма.

М.Базара, К.Шетти. Нелинейное программирование. Теория и алгоритмы. М.: Мир, 1982.

Использование

    int mnr6r_c (real *x, real *xe, integer *i0, real *a, real *b,
                 integer *n, S_fp func, real *f, real *fe, S_fp grad, real *g,
                 real *ge, real *up, real *rm, integer *irm, real *tmax, integer *ierr)

Параметры

x - вещественный вектор длины  n; при обращении к подпрограмме содержит заданную начальную точку поиска, на выходе содержит точку минимального вычисленного значения  f (x);
xe - вещественный вектор длины  n, задающий точность решения задачи по аргументу;
i0 - целый вектор длины  n, задающий фиксированные на время минимизации компоненты вектора  x: если i0 (j) = 0, то  j - я компонента вектора  x остается равной своему начальному значению; в противном случае i0 (j) = 1;
a - вещественный вектор длины  n, задающий ограничения снизу на переменные;
b - вещественный вектор длины  n, задающий ограничения сверху на переменные;
n - размерность пространства переменных (тип: целый);
func - имя подпрограммы вычисления значения функции  f (x) (см. замечания по использованию);
f - вещественная переменная, содержащая вычисленное минимальное значение  f (x);
fe - заданная точность решения задачи по функционалу (тип: вещественный);
grad - имя подпрограммы вычисления градиента функции  f (x) (см. замечания по использованию);
g - вещественный вектор длины  n, содержащий градиент функции;
ge - вещественный вектор длины  n, задающий точность решения задачи по градиенту;
up - вещественный вектор длины 4, задающий управляющие параметры алгоритма:
up(1) - заданная относительная погрешность, позволяющая управлять счетом;
up(2) - заданное положительное целое число, используемое в критерии замедления счета (см. замечания по использованию);
up(3) - заданное вещественное число большее единицы, используемое в критерии замедления счета;
up(4) - вещественное число большее единицы, задающее значение константы дробления шага;
rm - вещественный вектор длины 3 + 3n + n2;
rm(1) - на входе - заданное допустимое число итераций, на выходе - выполненное число итераций;
rm(2) - выполненное число вычислений функции;
rm(3) - выполненное число вычислений градиента;
  остальные элементы массива rm используются как рабочие;
irm - целый вектор длины  n, используемый как рабочий;
tmax - вещественная переменная, содержащая заданное время счета (в сек.);
ierr - целая переменная, указывающая причину окончания счета:
ierr=1 - найден минимум с заданной точностью по аргументу;
ierr=2 - найден минимум с заданной точностью по функционалу;
ierr=3 - найден минимум с заданной точностью по градиенту;
ierr=4 - выполнено заданное число итераций;
ierr=5 - истекло время;
ierr=6 - произошло замедление счета.

Версии

mnr6d_c - решение задачи минимизации дифференцируемой функции многих переменных при наличии двусторонних ограничений на переменные методом Дэвидона - Флетчера - Пауэлла с двойной точностью. Все вещественные массивы и переменные, кроме tmax и up, должны иметь тип double.

Вызываемые подпрограммы: нет

Замечания по использованию

 

Подпрограммы func и grad составляются пользователем.
Первый оператор подпрограммы вычисления функции должен иметь вид:

          int func (float *x, float *f, float *fe)
       Параметры:
       x   - вещественный вектор длины  n, задающий точку
               пространства, в которой вычисляется значение функции;
       f   - вещественная переменная, содержащая вычисленное
               значение функции в точке  x;
       fe - вещественная переменная, содержащая на входе 
               заданную точность вычисления значения функции в
               точке  x, а на выходе - достигнутую точность. 

В теле подпрограммы func параметр fe не должен переопределяться.

Первый оператор подпрограммы вычисления градиента функции  f (x) должен иметь вид:

           int grad  (float *x, float *g, float *ge, int *i0)
        Параметры:
        x   - вещественный вектор длины  n, задающий точку
                пространства, в которой вычисляется градиент;
        g   - вещественный вектор длины  n, содержащий
                градиент функции в точке  x;
        ge - вещественный вектор длины  n, содержащий на
                входе заданную покомпонентную точность
                вычисления градиента функции, на выходе -
                достигнутую точность вычисления градиента;
        i0  - целый вектор, управляющий вычислением градиента:
                если i0(j) = 0, то полагается g(j) = 0.
                Значение ge в теле подпрограммы не должно
                переопределяться. 

Фактические точности вычисления функции и градиента не должны быть меньше заданных. Во многих практических задачах вычисления с меньшей точностью требуют меньшего времени.

Управляющие параметры:
  up (1)  [ 0.01 ÷ 0.001 ] позволяет временно фиксировать компоненты, по которым функция медленно меняется, подбирается экспериментально;
  up (2)  - целое число от 2 до 15 - количество подряд идущих итераций, за которые изменения функции должны уменьшиться в up (3) раз;
  up (3)  [ 1.1 ÷ 10. ];
  up (4) > 1.,  up (4)  [ 1.2 ÷ 100. ] - параметр дробления отрезка на котором минимизируется функция; корректируется в процессе счета
 

Параметры up (2) и up (3) используются в критерии замедления счета. С помощью этого критерия фиксируются ситуации, когда изменения функции на каждой итерации на несколько порядков меньше, чем разность между текущим значением и минимальным.

В начале счета и перед выходом из подпрограммы фиксируются значения счетчика времени центрального процессора. tmax - допустимое время работы центрального процессора, которое пользователь отводит для решения задачи (в сек.).

Если счет закончился при одновременном выполнении нескольких критериев, значение ierr состоит из нескольких цифр. Каждая цифра расшифровывается отдельно, например, ierr = 15 означает, что ierr = 1 и ierr = 5, т.е. достигнута точность по аргументу и истекло время.

Используются служебные подпрограммы: mlu01_c, mnr11_c, mnr1n_c, mnr1q_c, mnr2d_c, mmkrit_c, utmn05_c, utmn06_c, mnr6f_c, mnr64_c, mnrug_c, mnru3_c.

Пример использования

Найти минимальное значение функции 
      f(x)  =  ( x2 - x12 )2 + ( 1 - x1 )2

    - 1.3 ≤ x1 ≤ 0.5 ,   0.5 ≤ x2 ≤ 1.    

Начальное приближение     x0  =  ( - 1.2, 1. )

Точное решение:     x* = (0.5, 0.5) ,    f* = 0.3125


int main(void)
{
    /* Initialized data */
    static float x[2] = { -1.2f,1.f };
    static float tmax = 30.f;
    static int n = 2;
    static float xe[2] = { 1e-18f,1e-18f };
    static float fe = 1e-18f;
    static float a[2] = { -1.3f,.5f };
    static float b[2] = { .5f,1.f };
    static int i0[2] = { 1,1 };
    static float rm[15] = { 100.f };
    static float ge[2] = { 1e-10f,1e-10f };
    static float up[4] = { 1e-15f,10.f,1.2f,100.f };

    /* Local variables */
    extern int grad_c(), func_c();
    static int ierr;
    extern int mnr6r_c(float *, float *, int *, float *, float *, int *,
                       U_fp, float *, float *, U_fp, float *, float *,
                       float *, float *, int *, float *, int *);
    static float f, g[2];
    extern int utmn05_c(float *);
    static float t0, t1, dt;
    static int irm[2];

    utmn05_c(&t0);
    printf("\n %11.3e %11.3e \n", x[0], x[1]);
    printf("\n %11.3e %11.3e \n", a[0], a[1]);
    printf("\n %11.3e %11.3e \n", b[0], b[1]);
    printf("\n %11.3e %11.3e \n", xe[0], xe[1]);
    printf("\n %11.3e \n", fe);
    printf("\n %11.3e %11.3e \n", ge[0], ge[1]);
    printf("\n %11.3e %11.3e %11.3e %11.3e \n\n", up[0], up[1], up[2], up[3]);

    mnr6r_c(x, xe, i0, a, b, &n, (U_fp)func_c, &f, &fe, (U_fp)grad_c, g, ge,
            up, rm, irm, &tmax, &ierr);

    utmn05_c(&t1);
    dt = t1 - t0;
    printf("\n %11.3e %11.3e %11.3e \n", rm[0], rm[1], rm[2]);
    printf("\n %5i \n", ierr);
    printf("\n %11.3e %11.3e \n", f);
    printf("\n %11.3e %11.3e \n", x[0], x[1]);
    printf("\n %11.3e %11.3e \n", g[0], g[1]);
    printf("\n %6.2f \n", dt);
    return 0;
} /* main */

int func_c(float *x, float *f, float *fe)
{
    /* System generated locals */
    float r__1, r__2, r__3;

    /* Parameter adjustments */
    --x;

    /* Function Body */
/* Computing 2nd power */
    r__2 = x[1];
/* Computing 2nd power */
    r__1 = x[2] - r__2 * r__2;
/* Computing 2nd power */
    r__3 = 1.f - x[1];
    *f = r__1 * r__1 + r__3 * r__3;
    return 0;
} /* func_c */

int grad_c(float *x, float *g, float *ge, int *i0)
{
    /* System generated locals */
    float r__1;

    /* Parameter adjustments */
    --i0;
    --ge;
    --g;
    --x;

    /* Function Body */
    g[1] = 0.f;
    if (i0[1] == 0) {
        goto l10;
    }
/* Computing 2nd power */
    r__1 = x[1];
    g[1] = (x[2] - r__1 * r__1) * -4.f * x[1] - (1.f - x[1]) * 2.f;
l10:
    g[2] = 0.f;
    if (i0[2] == 0) {
        goto l20;
    }
/* Computing 2nd power */
    r__1 = x[1];
    g[2] = (x[2] - r__1 * r__1) * 2.f;
l20:
    return 0;
} /* grad_c */


Результаты: 

      ierr = 1      f = 0.313      x = (0.5, 0.5) 
      rm(1) = 7    rm(2) = 8       rm(3) = 4