我有一个矩阵:
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];
答案 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