Этот пример показывает, как постараться не вызывать функцию дважды, когда он вычисляет значения и для цели и для ограничений с помощью основанного на решателе подхода. Чтобы постараться не вызывать функцию дважды с помощью основанного на проблеме подхода, смотрите Цель и Ограничения, Имеющие Общую Функцию в Последовательном или Параллельном, Основанном на проблеме.
Вы обычно используете такую функцию в симуляции. Решатели, такие как fmincon
выполняют объективные и нелинейные ограничительные функции отдельно. Эта оценка расточительна, когда вы используете то же вычисление для обоих результатов.
Чтобы постараться не напрасно тратить время, имейте свое использование вычисления вложенная функция, чтобы оценить цель и ограничительные функции только при необходимости путем сохранения значений длительных вычислений. Используя вложенную функцию избегает использования глобальных переменных, все же позволяет промежуточным результатам быть сохраненными и совместно использованными ограничительными функциями и целью.
Из-за пути ga
вызывает нелинейные ограничительные функции, метод в этом примере обычно не сокращает количество вызовов ограничительных функций или цели.
Шаг 2. Встройте функцию во вложенную функцию, которая сохраняет недавние значения.
Шаг 5. Сэкономьте вычислительное время с параллельными вычислениями.
Например, предположите, что computeall
является дорогой (длительной) функцией, вызванной и целевой функцией и нелинейными ограничительными функциями. Предположим, что вы хотите использовать fmincon
в качестве своего оптимизатора.
Запишите функцию, которая вычисляет фрагмент функционального f1
Розенброка и нелинейного ограничения c1
, который сохраняет решение в диске радиуса 1 вокруг источника. Функция Розенброка
который имеет уникальное минимальное значение 0 в (1,1). Смотрите Решают Ограниченную Нелинейную проблему, Основанную на решателе.
В этом примере нет никакого нелинейного ограничения равенства, таким образом , ceq1 = []
. Добавьте оператор pause(1)
, чтобы моделировать дорогое вычисление.
function [f1,c1,ceq1] = computeall(x) ceq1 = []; c1 = norm(x)^2 - 1; f1 = 100*(x(2) - x(1)^2)^2 + (1-x(1))^2; pause(1) % simulate expensive computation end
Сохраните computeall.m
как файл на вашем пути MATLAB®.
Предположим, что целевая функция
y = 100 (x 2 – x 12) 2 + (1 – x 1) 2
+ 20* (x 3 – x 42) 2 + 5* (1 – x 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 functions c = myc; % In this case, the computation is trivial ceq = myceq; end end
Сохраните вложенную функцию как файл с именем runobjconstr.m
на вашем пути MATLAB.
Петляйте, синхронизируя вызов с 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 203.797275 seconds.
Сравните времена, чтобы запустить решатель с и без вложенной функции. Для выполнения без вложенной функции сохраните 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 406.771978 seconds.
Решатель берет в два раза длиннее, чем прежде, потому что он оценивает цель и ограничение отдельно.
Если у вас есть лицензия Parallel Computing Toolbox™, можно сэкономить еще больше времени путем установки опции UseParallel
на true
.
parpool
Starting parallel pool (parpool) using the 'local' profile ... connected to 4 workers. ans = Pool with properties: Connected: true NumWorkers: 4 Cluster: local AttachedFiles: {} IdleTimeout: 30 minute(s) (30 minutes remaining) SpmdEnabled: true
opts = optimoptions(opts,'UseParallel',true);
tic
[x,fval,exitflag,output] = runobjconstr(x0,opts);
toc
Elapsed time is 97.528110 seconds.
В этом случае включение параллельных вычислений сокращает вычислительное время в половине.
Сравните выполнения с параллельными вычислениями, с и без вложенной функции:
tic
[x,fval,exitflag,output] = fmincon(@myrosen2,x0,...
[],[],[],[],[],[],@constr,opts);
toc
Elapsed time is 188.985178 seconds.
В этом примере, вычисляя параллельно, но не вложенный берет в то же время в качестве вычисления вложенного, но не параллельный. Вычисление и вложенного и параллель берет половину времени использования любого одного.