Повышение точности и эффективности при оптимизации

Этот пример демонстрирует, что Symbolic Math Toolbox помогает минимизировать ошибки при решении нелинейной системы уравнений.

В этом примере используются следующие возможности Symbolic Math Toolbox:

  • Вычисление аналитического градиента с помощью gradient

  • Вычисление аналитического якобиана с помощью jacobian

  • Преобразование символьных результатов в числовые функции с помощью matlabFunction

  • Аналитическая визуализация с fplot

Цель состоит в том, чтобы найти минимум функции Розенброка, или так называемой функции «банана».

f(x)=i=1n/2100(x2i-x2i-12)2+(1-x2i-1)2

Использование fplot чтобы создать быструю визуализацию функции Розенброка из двух переменных

syms x y
a=1;    b=100;
f(x,y)=(a-x)^2+b*(y-x^2)^2
f(x, y) = x-12+100y-x22(x - 1) ^ 2 + 100 * (y - x ^ 2) ^ 2
fsurf(f,[-2 2 -1 3])
view([-45 50])
colormap jet
caxis([0,1000])
colorbar

Figure contains an axes. The axes contains an object of type functionsurface.

Мотивация

Пример «Нелинейные уравнения с аналитическим якобианом» в Optimization Toolbox решает ту же задачу при помощи fsolve функция. Рабочий процесс, показанный в этом примере, имеет два потенциальных источника ошибок. Вам нужно будет

  1. Переведите уравнения для функции Розенброка и якобиана из математической формы в тексте в числовой код.

  2. Явно вычислите якобиан. Для сложных уравнений эта задача подвержена ошибкам.

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

Перепишите функцию Розенброка как систему нелинейных уравнений

Сначала преобразуйте функцию Розенброка f в систему нелинейных уравнений F, где F является градиентом f.

clear
n = 64;
x = sym('x',[n,1]);
f = sum(100*(x(2:2:n)-x(1:2:n).^2).^2 + (1-x(1:2:n)).^2);
F = gradient(f,x);

Показать первые 10 уравнений:

F(1:10)
ans = 

(2x1-400x1x2-x12-2200x2-200x122x3-400x3x4-x32-2200x4-200x322x5-400x5x6-x52-2200x6-200x522x7-400x7x8-x72-2200x8-200x722x9-400x9x10-x92-2200x10-200x92)[2 * x1 - 400 * x1 * (x2 - x1 ^ 2) - 2; 200 * x2 - 200 * x1 ^ 2; 2 * x3 - 400 * x3 * (x4 - x3 ^ 2) - 2; 200 * x4 - 200 * x3 ^ 2; 2 * x5 - 400 * x5 * (x6 - x5 ^ 2) - 2; 200 * x6 - 200 * x5 ^ 2; 2 * x7 - 400 * x7 * (x8 - x7 ^ 2) - 2; 200 * x8 - 200 * x7 ^ 2; 2 * x9 - 400 * x9 * (x10 - x9 ^ 2) - 2; 200 * x10 - 200 * x9 ^ 2]

Чтобы соответствовать промежуточным результатам, показанным в примере Optimization Toolbox, используйте ту же форму F.

F(1:2:n) = simplify(F(1:2:n) + 2*x(1:2:n).*F(2:2:n));
F(1:2:n) = -F(1:2:n)/2;
F(2:2:n) = F(2:2:n)/20;

Теперь системы уравнений идентичны:

F(1:10)
ans = 

(1-x110x2-10x121-x310x4-10x321-x510x6-10x521-x710x8-10x721-x910x10-10x92)[1 - x1; 10 * x2 - 10 * x1 ^ 2; 1 - x3; 10 * x4 - 10 * x3 ^ 2; 1 - х5; 10 * x6 - 10 * x5 ^ 2; 1 - х7; 10 * x8 - 10 * x7 ^ 2; 1 - x9; 10 * x10 - 10 * x9 ^ 2]

Вычислите якобиан матрицы, представляющей систему уравнений

Использование jacobian вычислить якобиан F. Эта функция вычисляет якобиан символически, таким образом избегая ошибок, связанных с числовыми приближениями производных.

JF = jacobian(F,x);

Показать первые 10 строк и столбцов матрицы Якобия.

JF(1:10,1:10)
ans = 

(-1000000000-20x1100000000000-1000000000-20x3100000000000-1000000000-20x5100000000000-1000000000-20x7100000000000-1000000000-20x910)[-sym (1), sym (0), sym (0), sym (0), sym (0), sym (0), sym (0), sym (0), sym (0), sym (0); -20 * x1, sym (10), sym (0), sym (0), sym (0), sym (0). sym (0), sym (0), sym (1), sym (0), sym (0), sym (0), sym (0), sym (0), sym (0), sym (0), sym (0); sym (0), sym (0), -20 * x3, sym (10), sym (0), sym (0), sym (0), sym (0), sym (0), sym (0); sym (0), sym (0), sym (0), sym (0), -sym (1), sym (0), sym (0), sym (0), sym (0), sym (0); sym (0), sym (0), sym (0), sym (0), -20 * x5, sym (10), sym (0), sym (0), sym (0), sym (0); sym (0), sym (0), sym (0), sym (0), sym (0), sym (0), -sym (1), sym (0), sym (0), sym (0); sym (0), sym (0), sym (0), sym (0), sym (0), sym (0), -20 * x7, sym (10), sym (0), sym (0); sym (0), sym (0), sym (0), sym (0), sym (0), sym (0), sym (0), sym (0), -sym (1), sym (0); sym (0), sym (0), sym (0), sym (0), sym (0), sym (0), sym (0), sym (0), sym (0), -20 * x9, sym (10)]

Большинство элементов матрицы Якобия JF являются нулями. Тем не менее, когда вы преобразуете эту матрицу в функцию MATLAB, результатом является плотная числовая матрица. Часто операции с разреженными матрицами более эффективны, чем операции с плотными матрицами.

Поэтому, чтобы создать эффективный код, преобразуйте только ненулевые элементы JF в символьный вектор перед вызовом matlabFunction. is и js представление шаблона разреженности JF.

[is,js] = find(JF);
JF = JF(JF~=0);

Преобразуйте систему уравнений и якобиан в функцию MATLAB

Система уравнений F, представляющий функцию Розенброка, является символьной матрицей, которая состоит из символических выражений. Чтобы иметь возможность решить его с помощью fsolve function, преобразуйте эту систему в функцию MATLAB. На этом шаге удобно преобразовывать обе F и его якобиан, JF, в одну файловую функцию MATLAB, FJFfun. В принципе это позволяет F и JF чтобы повторно использовать переменные. Также можно преобразовать их в отдельные функции MATLAB.

matlabFunction([F;JF],'var',x,'file','FJFfun');

FJFfun принимает переменные как список, но fsolve ожидает вектор переменных. Функция genericObj преобразует вектор в список. Анонимная функция bananaObj определяется как исправление значений аргументов для genericObj. Обратите внимание на использование шаблона разреженности в функции genericObj. Далее обратите внимание, что такой подход к использованию FJFfun и genericObj вместе не привязано к конкретному выражению, представленному F и может использоваться как есть для любого F.

bananaobj = @(y) genericObj(y,@FJFfun,is,js)
bananaobj = function_handle with value:
    @(y)genericObj(y,@FJFfun,is,js)

Использование fsolve Численное решение системы нелинейных уравнений

Использование fsolve для системы уравнений, преобразованной в функцию MATLAB. Используйте начальную точку x (i) = -1,9 для нечетных индексов, и x (i) = 2 для четных индексов. Задайте 'Display' на 'iter' чтобы увидеть прогресс решателя. Задайте 'Jacobian' на 'on' использовать якобиан, заданный в bananaobj.

x0(1:n,1) = -1.9;
x0(2:2:n,1) = 2;
options = optimoptions(@fsolve,'Display','iter','Jacobian','on');
[sol1,Fsol,exitflag,output,JAC] = fsolve(bananaobj,x0,options);
                                         Norm of      First-order   Trust-region
 Iteration  Func-count     f(x)          step         optimality    radius
     0          1         8563.84                           615               1
     1          2         3093.71              1            329               1
     2          3         225.104            2.5           34.8             2.5
     3          4          212.48           6.25           34.1            6.25
     4          5          212.48           6.25           34.1            6.25
     5          6          212.48         1.5625           34.1            1.56
     6          7         116.793       0.390625           5.79           0.391
     7          8         109.947       0.390625          0.753           0.391
     8          9         99.4696       0.976563            1.2           0.977
     9         10         83.6416        2.44141           7.13            2.44
    10         11         77.7663        2.44141           9.94            2.44
    11         12         77.7663        2.44141           9.94            2.44
    12         13          43.013       0.610352           1.38            0.61
    13         14         36.4334       0.610352           1.58            0.61
    14         15         34.1448        1.52588           6.71            1.53
    15         16         18.0108        1.52588           4.91            1.53
    16         17         8.48336        1.52588           3.74            1.53
    17         18         3.74566        1.52588           3.58            1.53
    18         19         1.46166        1.52588           3.32            1.53
    19         20         0.29997        1.24265           1.94            1.53
    20         21               0      0.0547695              0            1.53

Equation solved.

fsolve completed because the vector of function values is near zero
as measured by the value of the function tolerance, and
the problem appears regular as measured by the gradient.

Используйте vpasolve, чтобы численно решить систему нелинейных уравнений

Система нелинейных уравнений, F, может быть альтернативно решено с помощью vpasolve функция, которая является числовым решателем, доступным в Symbolic Math Toolbox. Ключевое различие между vpasolve и fsolve является ли это fsolve использует арифметику двойной точности, чтобы решить уравнения, тогда как vpasolve использует арифметику переменной точности и, следовательно, позволяет управлять точностью расчетов.

sol2 = vpasolve(F);

Если вы присвоите решение системы уравнений одной переменной, sol2, затем vpasolve возвращает решения в форме массива структур. Вы можете получить доступ к каждому решению (каждому полю массива структур):

sol2.x1
ans = 1.0vpa ('1.0')

Можно также преобразовать sol2 в символьный вектор, а затем доступ к области значений решений. Для примера отобразите решения с 5-го по 25-й:

for k=(1:64)
  sol2_array(k) = sol2.(char(x(k)));
end
sol2_array(5:25)
ans = (1.01.01.01.01.01.01.01.01.01.01.01.01.01.01.01.01.01.01.01.01.0)[vpa ('1.0'), vpa ('1.0'), vpa ('1.0'), vpa ('1.0'), vpa ('1.0'), vpa ('1.0'), vpa ('1.0'), vpa ('1.0'), vpa ('1.0'), vpa ('1.0')

Вспомогательные функции

function [F,J] = genericObj(x,FJFfun,is,js)
% genericObj takes as input, vector x, Function and Jacobian evaluation 
% function handle FJFfun, and sparsity pattern is,js and returns as output,
% the numeric values of the Function and Jacobian: F and Jfunction 
% FJs(1:length(x)) is the numeric vector for the Function
% FJs(length(x)+1:end) is the numeric vector for the non-zero entries of the Jacobian

xcell = num2cell(x);
FJs = FJFfun(xcell{:});
F = FJs(1:length(x));
J = sparse(is,js,FJs(length(x)+1:end));

end

Copyright © 2016 The MathWorks, Inc.