Суммирование без цикла for - MATLAB - PullRequest
4 голосов
/ 05 марта 2012

У меня есть 2 матрицы: V , который является квадратом MxM, и K , который является MxN. Вызывая измерение по строкам x и измерение по столбцам t, мне нужно оценить интеграл (то есть сумму) по обоим измерениям K , умноженный на t-сдвинутую версию V , ответ является функцией сдвига (почти как свертка, см. Ниже). Сумма определяется следующим выражением, где _{} обозначает индексы суммирования и дополняется нулями для запредельных элементов:

S(t) = sum_{x,tau}[V(x,t+tau) * K(x,tau)]

Мне удается сделать это с помощью одного цикла по измерению t (векторизация измерения x):

% some toy matrices
V = rand(50,50);
K = rand(50,10);
[M N] = size(K);

S = zeros(1, M);            
for t = 1 : N
  S(1,1:end-t+1) = S(1,1:end-t+1) + sum(bsxfun(@times, V(:,t:end),  K(:,t)),1);                
end 

У меня есть похожие выражения, которые мне удалось вычислить без цикла for, используя комбинацию conv2 и \ или зеркальное отображение (отражение) одного измерения. Однако я не вижу, как избежать цикла for в этом случае (несмотря на появившееся сходство со сверткой).

Ответы [ 2 ]

1 голос
/ 01 января 2016

Шаги к векторизации

1] Выполнить sum(bsxfun(@times, V(:,t:end), K(:,t)),1) для всех столбцов в V для всех столбцов в K с умножением матрицы -

sum_mults = V.'*K

Это даст нам двумерный массив с каждым столбцом, представляющим sum(bsxfun(@times,.. операцию на каждой итерации.

2] Шаг 1 дал нам все возможные суммы, а также значения, которые должны быть суммированы, не выровнены в одной и той же строке на протяжении итераций, поэтому нам нужно проделать еще немного работы перед суммированием по строкам. Остальная часть работы - получение сдвинутой версии. Для этого же вы можете использовать логическое индексирование с верхней и нижней треугольной логической маской. Наконец, мы суммируем по каждой строке для окончательного результата. Итак, эта часть кода будет выглядеть так -

valid_mask = tril(true(size(sum_mults)));
sum_mults_shifted = zeros(size(sum_mults));
sum_mults_shifted(flipud(valid_mask)) = sum_mults(valid_mask);
out = sum(sum_mults_shifted,2);

Испытания во время выполнения -

%// Inputs
V = rand(1000,1000);
K = rand(1000,200);

disp('--------------------- With original loopy approach')
tic
[M N] = size(K);
S = zeros(1, M);
for t = 1 : N
    S(1,1:end-t+1) = S(1,1:end-t+1) + sum(bsxfun(@times, V(:,t:end),  K(:,t)),1);
end
toc

disp('--------------------- With proposed vectorized approach')
tic
sum_mults = V.'*K; %//'
valid_mask = tril(true(size(sum_mults)));
sum_mults_shifted = zeros(size(sum_mults));
sum_mults_shifted(flipud(valid_mask)) = sum_mults(valid_mask);
out = sum(sum_mults_shifted,2);
toc

Вывод -

--------------------- With original loopy approach
Elapsed time is 2.696773 seconds.
--------------------- With proposed vectorized approach
Elapsed time is 0.044144 seconds.
0 голосов
/ 19 июля 2012

Это может быть обман (использование arrayfun вместо for цикла), но я считаю, что это выражение дает вам то, что вы хотите:

S = arrayfun(@(t) sum(sum( V(:,(t+1):(t+N)) .* K )), 1:(M-N), 'UniformOutput', true)
...