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