Улучшение производительности для многократного использования функции polyval - PullRequest
0 голосов
/ 23 октября 2018

У меня есть простой вопрос производительности при использовании поливальной функции с Matlab.

В настоящее время у меня есть вектор x, который может быть довольно длинным (> 1000 скаляров).Я хочу применить различные полиномиальные формы для каждого из х.

Полиномиальные формы хранятся в двумерном массиве и применяются в цикле, как показано ниже.Код относительно быстрый, так как polyval оптимизирован, но цикл может быть длинным, а производительность имеет первостепенное значение, поскольку это целевая функция, которую можно вычислить тысячи раз в процессе.

Есть идеи, как улучшить производительность?

Спасибо

% ---------- Objective Function ------------------
function [obj] = obj(x, poly_objective)
    polyvalue = zeros(length(x),1);
    for index = 1: length(x)
        polyvalue (index) = polyval(poly_objective(index,:), x(index));
    end
    obj= -sum(polyvalue );
end
% -------------------------------------------------

Ответы [ 3 ]

0 голосов
/ 23 октября 2018

Я нахожу ваш вопрос немного запутанным, но я думаю, что он делает то, что вы хотите:

polyvalue = sum(poly_objective .* x(:).^(numel(x)-1:-1:0), 2);

Обратите внимание, что в приведенном выше примере используется неявное расширение .Для версий Matlab до R2016b используйте bsxfun:

polyvalue = sum(poly_objective .* bsxfun(@power, x(:), (numel(x)-1:-1:0)), 2);

Пример

Случайные данные:

>> x = rand(1,4);
>> poly_objective = randi(9,4,4);

Ваш код:

>> polyvalue = zeros(length(x),1);
   for index = 1: length(x)
       polyvalue (index) = polyval(poly_objective(index,:), x(index));
   end
>> polyvalue
polyvalue =
  13.545710504297881
  16.286929525147158
  13.289183623920710
   5.777980886766799

Мой код:

>> polyvalue = sum(poly_objective .* x(:).^(numel(x)-1:-1:0), 2)
polyvalue =
  13.545710504297881
  16.286929525147158
  13.289183623920710
   5.777980886766799
0 голосов
/ 23 октября 2018

Самый быстрый способ, вероятно, оценивать различные полиномы напрямую, удаляя петлю (как показано obchardon или Luis ).Тем не менее, вот примечание о polyval производительности ...


Если вы введете edit polyval в командном окне, вы увидите источник функции polyval.В частности, в верхней части приведена следующая условная оценка:

nc = length(p);
if isscalar(x) && (nargin < 3) && nc>0 && isfinite(x) && all(isfinite(p(:)))
    % Make it scream for scalar x.  Polynomial evaluation can be
    % implemented as a recursive digital filter.
    y = filter(1,[1 -x],p);
    y = y(nc);
    return
end

Я думаю, что комментарий "Make it scream" является разработчиком (-ями), который говорит нам, что это очень быстрый путь через функцию!В сторону;это также лучший комментарий, который я нашел во встроенном в MATLAB.

Итак, давайте попробуем удовлетворить условия для этого if оператора ...

✓ isscalar(x)
✓ nargin < 3 
✓ length(p) > 0
✓ isfinite(x)
✓ all(isfinite(p(:)))

Бриллиант, такэто всегда оценка, которую вы используете.Вы можете найти улучшения в скорости, удалив эти 5 проверок и просто сделав это вместо polyval.С точки зрения ваших переменных это выглядит так:

y = filter(1,[1 -x(index)],poly_objective(index,:)); 
polyvalue (index) = y(size(poly_objective,2)); 
% Note you should get size(poly_objective,2) outside your loop
0 голосов
/ 23 октября 2018

Вы можете линеаризовать цикл for вручную, вот пример:

p = [3,2,1;  
     5,1,3];           %polynomial coeff
x = [5,6].';           %the query points
d = size(p,2)-1:-1:0;  %the power factors
res = sum(x.^d.*p,2);  %process all the polynome without for loop.

с

res =

    86
   189

Также, если вы оцените каждое значение x для каждого полинома, который вы можете использовать:

res = x.^d*p.'; %using only matrix multiplication

с

res =
       p1    p2
x1     86    133
x2     121   189
...