Получить много трехмерных матриц из двух двумерных матриц (умножение по столбцам)

Есть ли более быстрый способ выполнить следующую операцию без цикла?

n = 2;
m = 1000;
A = rand(n,m);
B = rand(n,m);

C = zeros(n*n,m);
for i = 1 : m
    tmp = A(:,i) * B(:,i)';
    C(:,i) = tmp(:);
end

В основном мне нужно получить mnxn матрицы с матричным умножением матриц между столбцами A а также B, Тогда мне нужна векторизация таких матриц.

2 ответа

Решение

Вы в основном выполняете поэлементное умножение для всех столбцов в A против всех столбцов, но транспонирован в B, Вы можете иметь один векторизованный подход с bsxfun(@times,..) в основном убивает / заменяет эти неприятные петли bsxfun мощные возможности внутреннего расширения. Реализация также будет включать изменение формы, чтобы оно было в том же формате, что и C и будет выглядеть примерно так -

out = reshape(bsxfun(@times,permute(A,[1 3 2]),permute(B,[3 1 2])),n^2,[]) 

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

В этом разделе сравниваются все перечисленные подходы для решения проблемы.

Код бенчмаркинга -

%// Inputs
n = 2;
m = 1000;
A = rand(n,m);
B = rand(n,m);

num_iter = 5000;

disp('-------------------- For loop NO fuN') %// From OP question
tic
for iter = 1:num_iter
    C = zeros(n*n,m);
    for i = 1 : m
        tmp = A(:,i) * B(:,i)';
        C(:,i) = tmp(:);
    end
end
toc

disp('-------------------- run run KRON') %'// @lhcgeneva's solution
tic
for iter = 1:num_iter
    A1 = repmat(A, n, 1);
    B1 = kron(B,ones(n,1));
    D = reshape(A1(:).*B1(:), n*n, m);
end
toc

disp('-------------------- fun fun BSXFUN') %// Proposed in this post
tic
for iter = 1:num_iter
    out = reshape(bsxfun(@times,permute(A,[1 3 2]),permute(B,[3 1 2])),n^2,[]);
end
toc

Выход -

-------------------- For loop NO fuN
Elapsed time is 28.101873 seconds.
-------------------- run run KRON
Elapsed time is 1.156337 seconds.
-------------------- fun fun BSXFUN
Elapsed time is 0.692433 seconds.

Вы можете полностью векторизовать это используя repmat, kron и reshape или, используя решение Divakar с bsxfun, permute а также repmat что дает вам еще одно значительное улучшение с точки зрения скорости.

tic
for j = 1:1000
A1 = repmat(A, n, 1);
B1 = kron(B,ones(n,1));
D = reshape(A1(:).*B1(:), n*n, m);
end
toc

Прошедшее время составляет 0,117396 секунд.

tic
for j = 1:1000
C = zeros(n*n,m);
for i = 1 : m
    tmp = A(:,i) * B(:,i)';
    C(:,i) = tmp(:);
end
end
toc

Прошедшее время составляет 5,751179 секунд.

Таким образом, ускорение составляет около 50 раз. Однако, как обсуждалось в комментариях ниже, ускорение, как обычно, зависит от размера матриц и количества выполнений задачи.

Другие вопросы по тегам