bsxfun在矩阵乘法中的实现

时间:2014-05-22 13:16:34

标签: performance matlab matrix matrix-multiplication bsxfun

一如既往地想要向您学习更多信息,我希望能通过以下代码获得一些帮助。

我需要完成以下任务:

1)我有一个矢量:

x = [1 2 3 4 5 6 7 8 9 10 11 12]

2)和矩阵:

A =[11    14    1
    5     8    18
    10    8    19
    13    20   16]

我需要能够将each的{​​{1}}值与x的{​​{1}}值相乘,这意味着:

every

这会给我A大小new_matrix = [1* A 2* A 3* A ... 12* A] 假设为new_matrix。在这种情况下(12*m x n)

如何使用matlab中的A (mxn)执行此操作?并且,这种方法会比(12*4x3)更快吗?

关于我的bsxfun,我在这里也需要一些帮助......当循环运行时,我无法存储每个for-loop :(

for-loop

提前致谢!!

编辑:在解决方案之后

第一个解决方案

"new_matrix"

输出:

for i=x
new_matrix = A.*x(i)
end

第二个解决方案

clear all
clc
x=1:0.1:50;
A = rand(1000,1000);
tic
val = bsxfun(@times,A,permute(x,[3 1 2]));
out = reshape(permute(val,[1 3 2]),size(val,1)*size(val,3),[]);
toc

输出:

Elapsed time is 7.597939 seconds.

5 个答案:

答案 0 :(得分:17)

x发送到第三维,以便当bsxfun用于与A进行相乘时,单例扩展生效,将产品结果扩展到第三维。然后,执行bsxfun乘法 -

val = bsxfun(@times,A,permute(x,[3 1 2])) 

现在,val3D矩阵,期望的输出应该是沿着第三维列的列连接的2D矩阵。这在下面实现 -

out = reshape(permute(val,[1 3 2]),size(val,1)*size(val,3),[])

希望有道理!传播bsxfun字!呜! :)

答案 1 :(得分:10)

kron函数就是这样:

kron(x.',A)

答案 2 :(得分:3)

以下是我目前提到的方法的基准,以及我自己的一些补充:

function [t,v] = testMatMult()
    % data
    %{
    x = [1 2 3 4 5 6 7 8 9 10 11 12];
    A = [11 14 1; 5 8 18; 10 8 19; 13 20 16];
    %}
    x = 1:50;
    A = randi(100, [1000,1000]);

    % functions to test
    fcns = {
        @() func1_repmat(A,x)
        @() func2_bsxfun_3rd_dim(A,x)
        @() func2_forloop_3rd_dim(A,x)
        @() func3_kron(A,x)
        @() func4_forloop_matrix(A,x)
        @() func5_forloop_cell(A,x)
        @() func6_arrayfun(A,x)
    };

    % timeit
    t = cellfun(@timeit, fcns, 'UniformOutput',true);

    % check results
    v = cellfun(@feval, fcns, 'UniformOutput',false);
    isequal(v{:})
    %for i=2:numel(v), assert(norm(v{1}-v{2}) < 1e-9), end
end

% Amro
function B = func1_repmat(A,x)
    B = repmat(x, size(A,1), 1);
    B = bsxfun(@times, B(:), repmat(A,numel(x),1));
end

% Divakar
function B = func2_bsxfun_3rd_dim(A,x)
    B = bsxfun(@times, A, permute(x, [3 1 2]));
    B = reshape(permute(B, [1 3 2]), [], size(A,2));
end

% Vissenbot
function B = func2_forloop_3rd_dim(A,x)
    B = zeros([size(A) numel(x)], 'like',A);
    for i=1:numel(x)
        B(:,:,i) = x(i) .* A;
    end
    B = reshape(permute(B, [1 3 2]), [], size(A,2));
end

% Luis Mendo
function B = func3_kron(A,x)
    B = kron(x(:), A);
end

% SergioHaram & TheMinion
function B = func4_forloop_matrix(A,x)
    [m,n] = size(A);
    p = numel(x);
    B = zeros(m*p,n, 'like',A);
    for i=1:numel(x)
        B((i-1)*m+1:i*m,:) = x(i) .* A;
    end
end

% Amro
function B = func5_forloop_cell(A,x)
    B = cell(numel(x),1);
    for i=1:numel(x)
        B{i} = x(i) .* A;
    end
    B = cell2mat(B);
    %B = vertcat(B{:});
end

% Amro
function B = func6_arrayfun(A,x)
    B = cell2mat(arrayfun(@(xx) xx.*A, x(:), 'UniformOutput',false));
end

我机器上的结果:

>> t
t =
    0.1650    %# repmat (Amro)
    0.2915    %# bsxfun in the 3rd dimension (Divakar)
    0.4200    %# for-loop in the 3rd dim (Vissenbot)
    0.1284    %# kron (Luis Mendo)
    0.2997    %# for-loop with indexing (SergioHaram & TheMinion)
    0.5160    %# for-loop with cell array (Amro)
    0.4854    %# arrayfun (Amro)

(这些时间可能会在不同的运行之间略有变化,但这应该让我们知道方法的比较方式)

请注意,其中一些方法会导致较大输入的内存不足错误(例如,基于repmat的解决方案很容易耗尽内存)。对于较大的尺寸,其他人会明显变慢,但由于耗尽的内存(例如kron解决方案)不会出错。

我认为bsxfun方法func2_bsxfun_3rd_dim或简单的for循环func4_forloop_matrix(感谢MATLAB JIT)是这种情况下的最佳解决方案。

当然,您可以更改上述基准参数(xA的大小)并得出您自己的结论:)

答案 3 :(得分:2)

只是为了添加替代方案,您可以使用cellfun来实现您想要的效果。这是一个例子(稍微修改一下):

x = randi(2, 5, 3)-1;
a = randi(3,3);
%// bsxfun 3D (As implemented in the accepted solution)
val = bsxfun(@and, a, permute(x', [3 1 2])); %//'
out = reshape(permute(val,[1 3 2]),size(val,1)*size(val,3),[]);
%// cellfun (My solution)
val2 = cellfun(@(z) bsxfun(@and, a, z), num2cell(x, 2), 'UniformOutput', false);
out2 = cell2mat(val2); % or use cat(3, val2{:}) to get a 3D matrix equivalent to val and then permute/reshape like for out
%// compare
disp(nnz(out ~= out2));

两者都给出了相同的结果。

有关使用cellfun的更多信息和技巧,请参阅:http://matlabgeeks.com/tips-tutorials/computation-using-cellfun/

还有:https://stackoverflow.com/a/1746422/1121352

答案 4 :(得分:0)

如果你的向量x长度为12且你的矩阵大小为3x4,我不认为使用其中一个会改变很多时间。如果你正在使用更大尺寸的矩阵和向量,那么现在可能会成为一个问题。

首先,我们希望将向量与矩阵相乘。在for循环方法中,这将提供类似的东西:

s = size(A);
new_matrix(s(1),s(2),numel(x)) = zeros;   %This is for pre-allocating. If you have a big vector or matrix, this will help a lot time efficiently.

for i = 1:numel(x)
    new_matrix(:,:,i)= A.*x(i)
end

这将为您提供3D矩阵,每个第三维都是乘法的结果。如果这不是您正在寻找的,我将添加另一个解决方案,使用更大的矩阵和向量可能会提高效率。