以下の関数は、私の問題の一部を解決するかもしれません。これは、times と mtimes のように、"mprod" と prod という名前が付けられています。いくつかの再形成により、multiprodを再帰的に使用します。一般に、再帰関数呼び出しはループよりも低速です。Multiprod は 100 倍以上高速であると主張しているため、それを補って余りあるはずです。
function sqMat = mprod(M)
% Multiply *many* square matrices together, stored
% as 3D array M. Speed gain through recursive use
% of function 'multiprod' (Leva, 2010).
% check if M consists of multiple matrices
if size(M,3) > 1
% check for odd number of matrices
if mod(size(M,3),2)
siz = size(M,1);
M = cat(3,M,eye(siz));
end
% create two smaller 3D arrays
X = M(:,:,1:2:end); % odd pages
Y = M(:,:,2:2:end); % even pages
% recursive call
sqMat = mprod(multiprod(X,Y));
else
% create final 2D matrix and break recursion
sqMat = M(:,:,1);
end
end
この機能の速度や精度はテストしていません。 これはループよりもはるかに高速だと思います。高次元では使用できないため、操作を「ベクトル化」しません。この関数を繰り返し使用する場合は、ループ内で行う必要があります。
EDIT以下は、十分に高速に動作するように見える新しいコードです。関数の再帰呼び出しは遅く、スタック メモリを消費します。まだループを含んでいますが、log(n)/log(2) だけループの数を減らします。また、より多くのディメンションのサポートが追加されました。
function sqMats = mprod(M)
% Multiply *many* square matrices together, stored along 3rd axis.
% Extra dimensions are conserved; use 'permute' to change axes of "M".
% Speed gained by recursive use of 'multiprod' (Leva, 2010).
% save extra dimensions, then reshape
dims = size(M);
M = reshape(M,dims(1),dims(2),dims(3),[]);
extraDim = size(M,4);
% Check if M consists of multiple matrices...
% split into two sets and multiply using multiprod, recursively
siz = size(M,3);
while siz > 1
% check for odd number of matrices
if mod(siz,2)
addOn = repmat(eye(size(M,1)),[1,1,1,extraDim]);
M = cat(3,M,addOn);
end
% create two smaller 3D arrays
X = M(:,:,1:2:end,:); % odd pages
Y = M(:,:,2:2:end,:); % even pages
% recursive call and actual matrix multiplication
M = multiprod(X,Y);
siz = size(M,3);
end
% reshape to original dimensions, minus the third axis.
dims(3) = [];
sqMats = reshape(M,dims);
end