Создайте эффективные задачи оптимизации

Когда задача имеет целочисленные ограничения, solve вызовы intlinprog для получения решения. Предложения по получению более быстрого решения или более целочисленно-допустимых точек см. в разделе Настройка целочисленного линейного программирования.

Прежде чем вы начнете решать проблему, иногда вы можете улучшить формулировку ваших ограничений задачи или цели. Обычно программа может создавать выражения для целевой функции или ограничений более быстро векторизованным способом, чем в цикле. Эта разность оборотов особенно велика, когда выражение оптимизации подлежит автоматической дифференциации; см. Раздел «Автоматическая дифференциация» в Optimization Toolbox.

Предположим, что ваша целевая функция

i=130j=130k=110xi,j,kbkci,j,

где x является переменной оптимизации, и b и c являются постоянными. Два общих способа сформулировать эту целевую функцию:

  • Использование for цикл.

    x = optimvar('x',30,30,10);
    b = optimvar('b',10);
    c = optimvar('c',30,30);
    tic
    expr = optimexpr;
    for i = 1:30
        for j = 1:30
            for k = 1:10
                expr = expr + x(i,j,k)*b(k)*c(i,j);
            end
        end
    end
    toc
    Elapsed time is 307.459465 seconds.

    Здесь, expr содержит выражение целевой функции. Хотя этот метод прост, он может потребовать чрезмерного времени, чтобы пройти цикл через многие уровни for циклы.

  • Используйте векторизованный оператор. Векторизованные операторы обычно выполняются быстрее, чем for цикл. Векторизованный оператор можно создать несколькими способами.

    • Разверните b и c. Чтобы включить умножение по срокам, создайте константы того же размера, что и x.

      tic
      bigb = reshape(b,1,1,10);
      bigb = repmat(bigb,30,30,1);
      bigc = repmat(c,1,1,10);
      expr = sum(sum(sum(x.*bigb.*bigc)));
      toc
      Elapsed time is 0.013631 seconds.
    • Цикл один раз по b.

      tic
      expr = optimexpr;
      for k = 1:10
          expr = expr + sum(sum(x(:,:,k).*c))*b(k);
      end
      toc
      Elapsed time is 0.044985 seconds.
    • Создайте выражение путем закольцовывания b а затем суммирование членов после цикла.

      tic
      expr = optimexpr(30,30,10);
      for k = 1:10
          expr(:,:,k) = x(:,:,k).*c*b(k);
      end
      expr = sum(expr(:));
      toc
      Elapsed time is 0.039518 seconds.

Наблюдайте разность оборотов между векторизованной и невекторизованной реализацией примера Ограниченная Электростатическая Нелинейная Оптимизация, Основанная на Проблеме. Этот пример был определен по времени с использованием автоматической дифференциации в R2020b.

N = 30;
x = optimvar('x',N,'LowerBound',-1,'UpperBound',1);
y = optimvar('y',N,'LowerBound',-1,'UpperBound',1);
z = optimvar('z',N,'LowerBound',-2,'UpperBound',0);
elecprob = optimproblem;
elecprob.Constraints.spherec = (x.^2 + y.^2 + (z+1).^2) <= 1;
elecprob.Constraints.plane1 = z <= -x-y;
elecprob.Constraints.plane2 = z <= -x+y;
elecprob.Constraints.plane3 = z <= x-y;
elecprob.Constraints.plane4 = z <= x+y;

rng default % For reproducibility
x0 = randn(N,3);
for ii=1:N
    x0(ii,:) = x0(ii,:)/norm(x0(ii,:))/2;
    x0(ii,3) = x0(ii,3) - 1;
end
init.x = x0(:,1);
init.y = x0(:,2);
init.z = x0(:,3);
opts = optimoptions('fmincon','Display','off');

tic
energy = optimexpr(1);
for ii = 1:(N-1)
    jj = (ii+1):N; % Vectorized
    tempe = (x(ii) - x(jj)).^2 + (y(ii) - y(jj)).^2 + (z(ii) - z(jj)).^2;
    energy = energy + sum(tempe.^(-1/2));
end
elecprob.Objective = energy;
disp('Vectorized computation time:')
[sol,fval,exitflag,output] = solve(elecprob,init,'Options',opts);
toc
Vectorized computation time:
Elapsed time is 1.838136 seconds.
tic
energy2 = optimexpr(1); % For nonvectorized comparison
for ii = 1:(N-1)
    for jjj = (ii+1):N; % Not vectorized
        energy2 = energy2 + ((x(ii) - x(jjj))^2 + (y(ii) - y(jjj))^2 + (z(ii) - z(jjj))^2)^(-1/2);
    end
end
elecprob.Objective = energy2;
disp('Non-vectorized computation time:')
[sol,fval,exitflag,output] = solve(elecprob,init,'Options',opts);
toc
Non-vectorized computation time:
Elapsed time is 204.615210 seconds.

Векторизованная версия примерно в 100 раз быстрее, чем невекторизованная версия.

Похожие темы