В этом примере показано, как избежать вызова функции дважды, когда она вычисляет значения как для цели, так и для ограничений с помощью основанного на проблеме подхода. Для основанного на решателе подхода см. «Объективные и нелинейные ограничения в одной функции».
Обычно вы используете такую функцию в симуляции. Решатели обычно вычисляют целевую и нелинейную функции ограничений отдельно. Эта оценка является расточительной при использовании одного и того же расчета для обоих результатов.
Этот пример также показывает эффект параллельных расчетов на скорость решателя. Что касается длительных функций, параллельные вычисления могут ускорить решатель, так как могут избежать многократного вызова трудоемкой функции в одной и той же точке. Использование обоих методов вместе ускоряет работу решателя больше всего.
The computeall
функция возвращает выходы, которые являются частью целевого и нелинейного ограничений.
type computeall
function [f1,c1] = computeall(x) c1 = norm(x)^2 - 1; f1 = 100*(x(2) - x(1)^2)^2 + (1 - x(1))^2; pause(1) % simulate expensive computation end
Функция включает в себя pause(1)
оператор для симуляции трудоемкой функции.
Эта задача использует четырехэлементную переменную оптимизации.
x = optimvar('x',4);
'ReuseEvaluation'
Преобразуйте computeall
функцию в выражение оптимизации. Чтобы сэкономить время во время оптимизации, используйте 'ReuseEvaluation'
Пара "имя-значение". Чтобы сэкономить время для определения решателя размеров выражений выхода (это происходит только один раз), установите 'OutputSize'
Пара "имя-значение" с [1 1]
, что указывает на то, что оба f
и c
являются скалярными .
[f,c] = fcn2optimexpr(@computeall,x,'ReuseEvaluation',true,'OutputSize',[1 1]);
Создайте целевую функцию из f
выражение.
obj = f + 20*(x(3) - x(4)^2)^2 + 5*(1 - x(4))^2;
Создайте нелинейное ограничение неравенства из c
выражение.
cons = c <= 0;
Создайте задачу оптимизации и включите цель и ограничение.
prob = optimproblem('Objective',obj);
prob.Constraints.cons = cons;
show(prob)
OptimizationProblem : Solve for: x minimize : ((arg3 + (20 .* (x(3) - x(4).^2).^2)) + (5 .* (1 - x(4)).^2)) where: [arg3,~] = computeall(x); subject to cons: arg_LHS <= 0 where: [~,arg_LHS] = computeall(x);
Отслеживайте время, необходимое для решения задачи, начиная с начальной точки x0.x = [-1;1;1;2]
.
x0.x = [-1;1;1;2];
x0.x = x0.x/norm(x0.x); % Feasible initial point
tic
[sol,fval,exitflag,output] = solve(prob,x0)
Solving problem using fmincon. 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>
sol = struct with fields:
x: [4×1 double]
fval = 0.7107
exitflag = OptimalSolution
output = struct with fields:
iterations: 25
funcCount: 149
constrviolation: 0
stepsize: 1.2914e-07
algorithm: 'interior-point'
firstorderopt: 4.0000e-07
cgiterations: 7
message: '↵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>↵↵Optimization completed: The relative first-order optimality measure, 2.909695e-07,↵is less than options.OptimalityTolerance = 1.000000e-06, and the relative maximum constraint↵violation, 0.000000e+00, is less than options.ConstraintTolerance = 1.000000e-06.↵↵'
solver: 'fmincon'
time1 = toc
time1 = 149.9299
Количество секунд для решения немного превышает количество вычислений функции, что указывает на то, что решатель вычислял каждую оценку только один раз.
fprintf("The number of seconds to solve was %g, and the number of evaluation points was %g.\n",time1,output.funcCount)
The number of seconds to solve was 149.93, and the number of evaluation points was 149.
Если вместо этого вы не вызываете fcn2optimexpr
использование 'ReuseEvaluation'
, затем время решения удваивается.
[f2,c2] = fcn2optimexpr(@computeall,x,'ReuseEvaluation',false); obj2 = f2 + 20*(x(3) - x(4)^2)^2 + 5*(1 - x(4))^2; cons2 = c2 <= 0; prob2 = optimproblem('Objective',obj2); prob2.Constraints.cons2 = cons2; tic [sol2,fval2,exitflag2,output2] = solve(prob2,x0);
Solving problem using fmincon. 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>
time2 = toc
time2 = 298.4493
Если у вас есть лицензия Parallel Computing Toolbox™, можно сэкономить еще больше времени, параллельно вычисляя. Для этого установите опции, чтобы использовать параллельную обработку и вызвать solve
с опциями.
options = optimoptions(prob,'UseParallel',true); tic [sol3,fval3,exitflag3,output3] = solve(prob,x0,'Options',options);
Solving problem using fmincon. 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>
time3 = toc
time3 = 74.7043
Использование параллельной обработки и 'ReuseEvaluation'
вместе обеспечивает более быстрое решение, чем использование 'ReuseEvaluation'
в одиночку. Посмотрите, сколько времени требуется, чтобы решить проблему, используя только параллельную обработку.
tic
[sol4,fval4,exitflag4,output4] = solve(prob2,x0,'Options',options);
Solving problem using fmincon. 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>
time4 = toc
time4 = 145.5278
Объедините результаты синхронизации в одну таблицу.
timingtable = table([time1;time2;time3;time4],... 'RowNames',["Reuse Serial";"No Reuse Serial";"Reuse Parallel";"No Reuse Parallel"])
timingtable=4×1 table
Var1
______
Reuse Serial 149.93
No Reuse Serial 298.45
Reuse Parallel 74.704
No Reuse Parallel 145.53
Для этой задачи на компьютере с 6-ядерным процессором параллельные вычисления занимают около половины времени последовательных вычислений и вычислений с 'ReuseEvaluation'
занимает около половины времени вычислений без 'ReuseEvaluation'
. Вычисления параллельно с 'ReuseEvaluation'
занимает около четверти времени вычисления последовательно без 'ReuseEvaluation'
.