exponenta event banner

Расчет градиентов и гессенов с помощью символьных математических Toolbox™

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

  • jacobian (Символьная математическая панель инструментов) создает градиент скалярной функции и создает матрицу частных производных векторной функции. Так, например, можно получить матрицу Гессена (вторые производные целевой функции), применив jacobian к градиенту. В этом примере показано, как использовать jacobian для создания символьных градиентов и гессенов функций объектива и ограничения.

  • matlabFunction(Панель инструментов символьной математики) создает анонимную функцию или файл, в котором вычисляются значения символьного выражения. В этом примере показано, как использовать matlabFunction для создания файлов, которые вычисляют функции цели и ограничения и их производные в произвольных точках.

Символьные математические функции панели инструментов имеют различные синтаксисы и структуры по сравнению с функциями Optimization Toolbox™. В частности, символьные переменные являются действительными или сложными скалярами, тогда как функции Optimization Toolbox передают векторные аргументы. Таким образом, необходимо предпринять несколько шагов, чтобы символически сгенерировать целевую функцию, ограничения и все их необходимые производные, в форме, подходящей для алгоритма внутренней точки fmincon.

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

Описание проблемы

Рассмотрим электростатическую задачу размещения 10 электронов в проводящем теле. Электроны располагаются таким образом, что сводят к минимуму их общую потенциальную энергию, подчиняясь ограничению лежания внутри тела. Все электроны находятся на границе тела как минимум. Электроны неразличимы, поэтому для этой задачи не существует уникального минимума (перестановка электронов в одном решении даёт другое действительное решение). Этот пример вдохновлен Доланом, Море и Мансоном [58].

Этот пример является проводящим органом, определяемым неравенствами

z≤-|x|-|y|

x2 + y2 + (z + 1) 2≤1.

Это тело похоже на пирамиду на сфере.

[X,Y] = meshgrid(-1:.01:1);
Z1 = -abs(X) - abs(Y);
Z2 = -1 - sqrt(1 - X.^2 - Y.^2);
Z2 = real(Z2);
W1 = Z1; W2 = Z2;
W1(Z1 < Z2) = nan; % Only plot points where Z1 > Z2
W2(Z1 < Z2) = nan; % Only plot points where Z1 > Z2
hand = figure; % Handle to the figure, for more plotting later
set(gcf,'Color','w') % White background
surf(X,Y,W1,'LineStyle','none');
hold on
surf(X,Y,W2,'LineStyle','none');
view(-44,18)

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

Создать переменные

Создание символьного вектора x как вектор 30 на 1, состоящий из вещественных символьных переменных xij, с i от 1 до 10, и j от 1 до 3. Эти переменные представляют три координаты электрона i: xi1 соответствует координате x, xi2 соответствует координате y и xi3 соответствует координате z.

x = cell(3, 10);
for i = 1:10
    for j = 1:3
        x{j,i} = sprintf('x%d%d',i,j);
    end
end
x = x(:); % Now x is a 30-by-1 vector
x = sym(x, 'real');

Отображение вектора x.

x
x = 

(x11x12x13x21x22x23x31x32x33x41x42x43x51x52x53x61x62x63x71x72x73x81x82x83x91x92x93x101x102x103)[x11; x12; x13; x21; x22; x23; x31; x32; x33; x41; x42; x43; x51; x52; x53; x61; x62; x63; x71; x72; x73; x81; x82; x83; x91; x92; x93; x101; x102; x103]

Включить линейные зависимости

Запишите линейные зависимости

z≤-|x|-|y|

как набор из четырех линейных неравенств для каждого электрона:

xi3 - xi1 - xi2 ≤ 0
xi3 - xi1 + xi2 ≤ 0
xi3 + xi1 - xi2 ≤ 0
xi3 + xi1 + xi2 ≤ 0

Итак, эта проблема имеет в общей сложности 40 линейных неравенств.

Запишите неравенства структурированным образом.

B = [1,1,1;-1,1,1;1,-1,1;-1,-1,1];

A = zeros(40,30);
for i=1:10
    A(4*i-3:4*i,3*i-2:3*i) = B;
end

b = zeros(40,1);

Вы можете видеть, что A*x ≤ b представляет собой неравенство.

disp(A*x)

(x11+x12+x13x12-x11+x13x11-x12+x13x13-x12-x11x21+x22+x23x22-x21+x23x21-x22+x23x23-x22-x21x31+x32+x33x32-x31+x33x31-x32+x33x33-x32-x31x41+x42+x43x42-x41+x43x41-x42+x43x43-x42-x41x51+x52+x53x52-x51+x53x51-x52+x53x53-x52-x51x61+x62+x63x62-x61+x63x61-x62+x63x63-x62-x61x71+x72+x73x72-x71+x73x71-x72+x73x73-x72-x71x81+x82+x83x82-x81+x83x81-x82+x83x83-x82-x81x91+x92+x93x92-x91+x93x91-x92+x93x93-x92-x91x101+x102+x103x102-x101+x103x101-x102+x103x103-x102-x101)[x11 + x12 + x13; x12 - x11 + x13; x11 - x12 + x13; x13 - x12 - x11; x21 + x22 + x23; x22 - x21 + x23; x21 - x22 + x23; x23 - x22 - x21; x31 + x32 + x33; x32 - x31 + x33; x31 - x32 + x33; x33 - x32 - x31; x41 + x42 + x43; x42 - x41 + x43; x41 - x42 + x43; x43 - x42 - x41; x51 + x52 + x53; x52 - x51 + x53; x51 - x52 + x53; x53 - x52 - x51; x61 + x62 + x63; x62 - x61 + x63; x61 - x62 + x63; x63 - x62 - x61; x71 + x72 + x73; x72 - x71 + x73; x71 - x72 + x73; x73 - x72 - x71; x81 + x82 + x83; x82 - x81 + x83; x81 - x82 + x83; x83 - x82 - x81; x91 + x92 + x93; x92 - x91 + x93; x91 - x92 + x93; x93 - x92 - x91; x101 + x102 + x103; x102 - x101 + x103; x101 - x102 + x103; x103 - x102 - x101]

Создание нелинейных зависимостей и их градиентов и гессенов

Нелинейные ограничения также структурированы.

x2 + y2 + (z + 1) 2≤1.

Создание зависимостей и их градиентов и гессенов.

c = sym(zeros(1,10));
i = 1:10;
c = (x(3*i-2).^2 + x(3*i-1).^2 + (x(3*i)+1).^2 - 1).';

gradc = jacobian(c,x).'; % .' performs transpose

hessc = cell(1, 10);
for i = 1:10
    hessc{i} = jacobian(gradc(:,i),x);
end

Вектор зависимости c является вектором строки и градиентом c(i) представлен в iтретий столбец матрицы gradc. Эта форма является правильной, как описано в разделе Нелинейные ограничения.

Гессенские матрицы, hessc{1}, ..., hessc{10}, квадратные и симметричные. Этот пример хранит их в массиве ячеек, что лучше, чем хранить их в отдельных переменных, таких как hessc1, ..., hessc10.

Используйте .' синтаксис для транспонирования. ' синтаксис означает сопряженное транспонирование, которое имеет различные символьные производные.

Создание целевой функции и ее градиента и гессена

Целевая функция, потенциальная энергия, представляет собой сумму обратных расстояний между каждой электронной парой.

energy=∑i<j1|xi-xj|.

Расстояние - это квадратный корень из суммы квадратов разностей в компонентах векторов.

Вычислите энергию (целевую функцию) и её градиент и гессен.

energy = sym(0);
for i = 1:3:25
    for j = i+3:3:28
        dist = x(i:i+2) - x(j:j+2);
        energy = energy + 1/sqrt(dist.'*dist);
    end
end

gradenergy = jacobian(energy,x).';

hessenergy = jacobian(gradenergy,x);

Создание файла целевой функции

Целевая функция имеет два выхода, energy и gradenergy. Поместить обе функции в один вектор при вызове matlabFunction уменьшить количество вложенных выражений, которые matlabFunction генерирует и возвращает градиент только тогда, когда вызывающая функция (fmincon в этом случае) запрашивает оба выхода. Полученные файлы можно поместить в любую папку по пути MATLAB. В этом случае поместите их в текущую папку.

currdir = [pwd filesep]; % You might need to use currdir = pwd 
filename = [currdir,'demoenergy.m'];
matlabFunction(energy,gradenergy,'file',filename,'vars',{x});

matlabFunction прибыль energy в качестве первого выхода и gradenergy как второй. Функция также принимает один входной вектор {x} вместо списка входных данных x11, ..., x103.

Результирующий файл demoenergy.m содержит следующие строки или подобные строки:

function [energy,gradenergy] = demoenergy(in1)
%DEMOENERGY
%   [ENERGY,GRADENERGY] = DEMOENERGY(IN1)
...
x101 = in1(28,:);
...
energy = 1./t140.^(1./2) + ...;
if nargout > 1
    ...
    gradenergy = [(t174.*(t185 - 2.*x11))./2 - ...];
end

Эта функция имеет правильный вид для целевой функции с градиентом; см. раздел Запись скалярных целевых функций.

Создание файла функции ограничения

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

filename = [currdir,'democonstr.m'];
matlabFunction(c,[],gradc,[],'file',filename,'vars',{x},...
    'outputs',{'c','ceq','gradc','gradceq'});

Результирующий файл democonstr.m содержит следующие строки или подобные строки:

function [c,ceq,gradc,gradceq] = democonstr(in1)
%DEMOCONSTR
%    [C,CEQ,GRADC,GRADCEQ] = DEMOCONSTR(IN1)
...
x101 = in1(28,:);
...
c = [t417.^2 + ...];
if nargout > 1
    ceq = [];
end
if nargout > 2
    gradc = [2.*x11,...];
end
if nargout > 3
    gradceq = [];
end

Эта функция имеет правильный вид для функции ограничения с градиентом; см. раздел Нелинейные ограничения.

Создание гессенских файлов

Чтобы сгенерировать гессен лагранжиана для проблемы, сначала генерируйте файлы для энергии гессена и ограничения гессенов.

Гессен целевой функции, hessenergy, является большим символьным выражением, содержащим более 150 000 символов, как показано при оценке size(char(hessenergy)). Итак, бегать matlabFunction(hessenergy) занимает значительное количество времени.

Создать файл hessenergy.m.

filename = [currdir,'hessenergy.m'];
matlabFunction(hessenergy,'file',filename,'vars',{x});

В противоположность этому гессенцы функций ограничения малы и быстры в вычислении.

for i = 1:10
    ii = num2str(i);
    thename = ['hessc',ii];
    filename = [currdir,thename,'.m'];
    matlabFunction(hessc{i},'file',filename,'vars',{x});
end

После создания всех файлов для цели и ограничений, сложите их с соответствующими множителями Лагранжа в вспомогательную функцию hessfinal.m, код которого появляется в конце этого примера.

Запустить оптимизацию

Начните оптимизацию с электронов, распределенных случайным образом по сфере радиуса 1/2 с центром в [0,0, -1].

rng default % For reproducibility
Xinitial = randn(3,10); % Columns are normal 3-D vectors
for j=1:10
    Xinitial(:,j) = Xinitial(:,j)/norm(Xinitial(:,j))/2;
    % This normalizes to a 1/2-sphere
end
Xinitial(3,:) = Xinitial(3,:) - 1; % Center at [0,0,-1]
Xinitial = Xinitial(:); % Convert to a column vector

Задайте параметры для использования interior-point и использовать градиенты и гессенский.

options = optimoptions(@fmincon,'Algorithm','interior-point','SpecifyObjectiveGradient',true,...
    'SpecifyConstraintGradient',true,'HessianFcn',@hessfinal,'Display','final');

Звонить fmincon.

[xfinal,fval,exitflag,output] = fmincon(@demoenergy,Xinitial,...
    A,b,[],[],[],[],@democonstr,options);
Local minimum found that satisfies the constraints.

Optimization completed because the objective function is non-decreasing in 
feasible directions, to within the value of the optimality tolerance,
and constraints are satisfied to within the value of the constraint tolerance.

<stopping criteria details>

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

disp(fval)
   34.1365
disp(exitflag)
     1
disp(output.iterations)
    19
disp(output.funcCount)
    28

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

for i = 1:10
    plot3(xfinal(3*i-2),xfinal(3*i-1),xfinal(3*i),'r.','MarkerSize',25);
end

Для проверки всей геометрии 3-D поверните фигуру.

rotate3d

figure(hand)

Сравнение с оптимизацией без градиентов и гессенов

Использование градиентов и гессенов делает оптимизацию более быстрой и точной. Чтобы сравнить одну и ту же оптимизацию без градиента или гессенской информации, задайте параметры, чтобы не использовать градиенты и гессеновцы.

options = optimoptions(@fmincon,'Algorithm','interior-point',...
    'Display','final');
[xfinal2,fval2,exitflag2,output2] = fmincon(@demoenergy,Xinitial,...
    A,b,[],[],[],[],@democonstr,options);
Feasible point with lower objective function value found.


Local minimum found that satisfies the constraints.

Optimization completed because the objective function is non-decreasing in 
feasible directions, to within the value of the optimality tolerance,
and constraints are satisfied to within the value of the constraint tolerance.

<stopping criteria details>

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

disp(fval2)
   34.1365
disp(exitflag2)
     1
disp(output2.iterations)
    80
disp(output2.funcCount)
        2525

Сравните количество итераций и число оценок функций с информацией о производной и без нее.

tbl = table([output.iterations;output2.iterations],[output.funcCount;output2.funcCount],...
    'RowNames',{'With Derivatives','Without Derivatives'},'VariableNames',{'Iterations','Fevals'})
tbl=2×2 table
                           Iterations    Fevals
                           __________    ______

    With Derivatives           19           28 
    Without Derivatives        80         2525 

Очистить допущения символьной переменной

Символьные переменные в этом примере предполагают, что они являются реальными в рабочем пространстве символического механизма. Удаление переменных не устраняет это предположение из рабочего пространства символического механизма. Очистить допущения переменных с помощью syms.

syms x

Убедитесь, что допущения пусты.

assumptions(x)
 
ans =
 
Empty sym: 1-by-0
 

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

Следующий код создает hessfinal функция помощника.

function H = hessfinal(X,lambda)
%
% Call the function hessenergy to start
H = hessenergy(X);

% Add the Lagrange multipliers * the constraint Hessians
H = H + hessc1(X) * lambda.ineqnonlin(1);
H = H + hessc2(X) * lambda.ineqnonlin(2);
H = H + hessc3(X) * lambda.ineqnonlin(3);
H = H + hessc4(X) * lambda.ineqnonlin(4);
H = H + hessc5(X) * lambda.ineqnonlin(5);
H = H + hessc6(X) * lambda.ineqnonlin(6);
H = H + hessc7(X) * lambda.ineqnonlin(7);
H = H + hessc8(X) * lambda.ineqnonlin(8);
H = H + hessc9(X) * lambda.ineqnonlin(9);
H = H + hessc10(X) * lambda.ineqnonlin(10);
end

Связанные темы