矢量化:矩阵阵列乘法元素逐一

时间:2017-07-09 02:53:03

标签: matlab vectorization

我有一个矩阵:

R = [0 -1;1 0];

array = 1:1:10;

另外x0 = [2;1]

如何在没有循环的情况下以最有效的方式获得另一个数组?

array2 = [expm(1*R) expm(2*R) expm(3*R) .... expm(10*R)];

然后我想获得 维度2乘以10的array3

array3 = [expm(1*R)*x0 expm(2*R)*x0 expm(3*R)*x0 .... expm(10*R)*x0];

3 个答案:

答案 0 :(得分:2)

来自wikipedia

  

如果矩阵是对角线,则可以通过对主对角线上的每个条目取幂来获得指数。

假设可以从{1*R, 2*R,...}创建块对角矩阵,则可以获得其指数并将其重新整形为[2 * n],并且可以乘以x0。 但是它的性能可能比循环更差。

R = [0 -1;1 0];
array = 1:1:10;
x0 = [2;1]
n = numel(array);
result = reshape(expm(kron(spdiags(array.',0,n,n),R))*repmat(x0,n,1),2,[]);

对于小尺寸(小于70个元素)的array,全矩阵更有效:

result = reshape(expm(kron(diag(array),R))*repmat(x0,n,1),2,[]);

答案 1 :(得分:2)

嗯,我看到你拥有的矩阵R是2x2。如果它总是2x2,那么你可以使用以下函数(Wikipedia)来计算指数:

function output = expm2d(A)
% Assuming t = 1 from Evaluation by Laurent series (https://en.wikipedia.org/wiki/Matrix_exponential#Evaluation_by_Laurent_series)
s = trace(A) / 2;
q = sqrt(-det(A - s*eye(size(A))));
output = exp(s) * ((cosh(q) - s * sinh(q) / q) * eye(size(A)) + (sinh(q) * A / q));
end

使用thewaywewalk提供的出色比较功能,我得到了以下结果:

使用expm时:

>> bench
ans =
    0.0181 %// rahnema
    0.1075 %// thewaywewalk arrayfun
    0.1139 %// thewaywewalk accumarray

使用expm2d时:

>> bench
ans =
    0.0048 %// rahnema
    0.0161 %// thewaywewalk arrayfun
    0.0222 %// thewaywewalk accumarray

如您所见,使用2d矩阵函数会导致运行时间减少10倍。当然,当R不是2x2时,不能使用它。

编辑: 将expm2d用于A = 1:100时:

>> bench
ans =
    0.1379 %// rahnema
    0.1415 %// thewaywewalk arrayfun
    0.1756 %// thewaywewalk accumarray

答案 2 :(得分:1)

我仍然不知道我的问题是否正确。这里有两个解决方案,它们没有完全矢量化,但速度相当快:

R = [0 -1;1 0];
A = 1:1:10;
x0 = [2;1];

%// option 1
temp = arrayfun(@(x) (expm(R*x)*x0).', A, 'uni', 0);
array3 = vertcat( temp{:} )

%// option 2
temp = accumarray( (1:numel(A)).', A(:), [], @(x) {(expm(R*x)*x0).'})
array3 = vertcat( temp{:} )

基准

我没有考虑Leander's Answer,因为它没有计算array3

function [t] = bench()
    R = [0 -1;1 0];
    A = 1:1:10;
    x0 = [2;1];

    % functions to compare
    fcns = {
        @() compare1(A,R,x0);
        @() compare2(A,R,x0);
        @() compare3(A,R,x0);
    };

    % timeit
    t = zeros(3,1);
    for ii = 1:100;
        t = t + cellfun(@timeit, fcns);
    end
end

function array3 = compare1(A,R,x0)  %rahnema1
    n = numel(A);
    array3 = reshape(expm(kron(diag(A),R))*repmat(x0,n,1),2,[])
end
function array3 = compare2(A,R,x0)  %thewaywewalk 1
    temp = arrayfun(@(x) (expm(R*x)*x0).', A, 'uni', 0);
    array3 = vertcat( temp{:} )
end
function array3 = compare3(A,R,x0)  %thewaywewalk 2
    temp = accumarray( (1:numel(A)).', A(:), [], @(x) {(expm(R*x)*x0).'});
    array3 = vertcat( temp{:} )
end

<强>结果:

代表A = 1:1:10;

0.1006   %// rahnema
0.2831   %// thewaywewalk arrayfun
0.3103   %// thewaywewalk accumarray

由于kron大型数组的速度非常慢,基准测试结果会因A = 1:1:100;而发生变化:

4.0068   %// rahnema
1.8045   %// thewaywewalk arrayfun
2.4257   %// thewaywewalk accumarray