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