В этом примере показано, как постараться не вызывать функцию дважды, когда она вычисляет значения и для цели и для ограничений с помощью основанного на решателе подхода. Чтобы постараться не вызывать функцию дважды с помощью подхода, основанного на проблеме, смотрите Цель и Ограничения, Имеющие Общую Функцию в Последовательном или Параллельном, Основанном на проблеме.
Вы обычно используете такую функцию в симуляции. Решатели, такие как 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.
В этом примере, вычисляя параллельно, но не вложенный берет в то же время в качестве вычисления вложенного, но не параллельный. Вычисление и вложенного и параллель берет половину времени использования любого одного.