Целевые и нелинейные ограничения в одной функции

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

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

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

Примечание

Из-за пути ga (Global Optimization Toolbox) вызывает нелинейные функции ограничения, метод в этом примере обычно не уменьшает количество вызовов в цель или функции ограничения.

Шаг 1. Написание функции, которая вычисляет цель и ограничения.

Например, предположим computeall - дорогая (длительная) функция, вызываемая как целевой функцией, так и нелинейными ограничительными функциями. Предположим, что вы хотите использовать fmincon как ваш оптимизатор.

Написание функции, которая вычисляет фрагмент функции Розенбрка f1 и включает нелинейное ограничение c1 который сохраняет решение в диске радиуса 1 вокруг источника. Функция Розенбрка

f(x)=100(x2x12)2+(1x1)2,

который имеет уникальное минимальное значение 0 в (1,1). См. Решение ограниченной нелинейной задачи, основанной на решателе.

Этот пример не имеет нелинейного ограничения равенства, так что   ceq1 = []. Добавление pause(1) оператор для моделирования дорогостоящих расчетов.

function [f1,c1,ceq1] = computeall(x)
    ceq1 = [];
    c1 = x(1)^2 + x(2)^2 - 1;
    f1 = 100*(x(2) - x(1)^2)^2 + (1-x(1))^2;
    pause(1) % Simulate expensive computation
end

Сохраните computeall.m как файл на MATLAB® путь.

Шаг 2. Встройте функцию во вложенную функцию, которая сохраняет последние значения.

Предположим, что целевая функция

y = 100 (x 2<reservedrangesplaceholder0> 12)2 + (1 – <reservedrangesplaceholder0> 1)2
+ 20* (x 3<reservedrangesplaceholder0> 42)2 + 5* (1 – <reservedrangesplaceholder0> 4)2.

computeall возвращает первую часть целевой функции. Встройте вызов в computeall во вложенной функции:

function [x,f,eflag,outpt] = runobjconstr(x0,opts)

if nargin == 1 % No options supplied
    opts = [];
end

xLast = []; % Last place computeall was called
myf = []; % Use for objective at xLast
myc = []; % Use for nonlinear inequality constraint
myceq = []; % Use for nonlinear equality constraint

fun = @objfun; % The objective function, nested below
cfun = @constr; % The constraint function, nested below

% Call fmincon
[x,f,eflag,outpt] = fmincon(fun,x0,[],[],[],[],[],[],cfun,opts);

    function y = objfun(x)
        if ~isequal(x,xLast) % Check if computation is necessary
            [myf,myc,myceq] = computeall(x);
            xLast = x;
        end
        % Now compute objective function
        y = myf + 20*(x(3) - x(4)^2)^2 + 5*(1 - x(4))^2;
    end

    function [c,ceq] = constr(x)
        if ~isequal(x,xLast) % Check if computation is necessary
            [myf,myc,myceq] = computeall(x);
            xLast = x;
        end
        % Now compute constraint function
        c = myc; % In this case, the computation is trivial
        ceq = myceq;
    end

end

Сохраните вложенную функцию как файл с именем runobjconstr.m на пути MATLAB.

Шаг 3. Определите время выполнения с помощью вложенной функции.

Запустите функцию, синхронизируя вызов с tic и toc.

opts = optimoptions(@fmincon,'Algorithm','interior-point','Display','off');
x0 = [-1,1,1,2];
tic
[x,fval,exitflag,output] = runobjconstr(x0,opts);
toc
Elapsed time is 259.364090 seconds.

Шаг 4. Определите время выполнения без вложенной функции.

Сравните время запуска решателя с вложенной функцией и без нее. Для запуска без вложенной функции сохраните myrosen2.m как файл целевой функции и constr.m как ограничение.

function y = myrosen2(x)
    f1 = computeall(x); % Get first part of objective
    y = f1 + 20*(x(3) - x(4)^2)^2 + 5*(1 - x(4))^2;
end

function [c,ceq] = constr(x)
    [~,c,ceq] = computeall(x);
end

Управляемый fmincon, синхронизация вызова с tic и toc.

tic
[x,fval,exitflag,output] = fmincon(@myrosen2,x0,...
                   [],[],[],[],[],[],@constr,opts);
toc
Elapsed time is 518.364770 seconds.

Решатель занимает в два раза больше времени, чем раньше, потому что он оценивает цель и ограничение отдельно.

Шаг 5. Экономьте вычислительное время при параллельных вычислениях.

Если у вас есть лицензия Parallel Computing Toolbox™, можно сэкономить еще больше времени, установив UseParallel опция для true.

parpool
Starting parallel pool (parpool) using the 'local' profile ...
Connected to the parallel pool (number of workers: 6).

ans = 

 ProcessPool with properties: 

            Connected: true
           NumWorkers: 6
              Cluster: local
        AttachedFiles: {}
    AutoAddClientPath: true
          IdleTimeout: 30 minutes (30 minutes remaining)
          SpmdEnabled: true
opts = optimoptions(opts,'UseParallel',true);
tic
[x,fval,exitflag,output] = runobjconstr(x0,opts);
toc
Elapsed time is 121.151203 seconds.

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

Сравните запуски с параллельными вычислениями, с вложенной функцией и без нее:

tic
[x,fval,exitflag,output] = fmincon(@myrosen2,x0,...
                   [],[],[],[],[],[],@constr,opts);
toc
Elapsed time is 235.914597 seconds.

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

Похожие темы