AxBxCマトリックスX
とBxDマトリックスがあるとしY
ます。
C AxB行列のそれぞれを で乗算できるループ以外の方法はありY
ますか?
AxBxCマトリックスX
とBxDマトリックスがあるとしY
ます。
C AxB行列のそれぞれを で乗算できるループ以外の方法はありY
ますか?
個人的な好みとして、コードはできるだけ簡潔で読みやすいものにしたいと思っています。
「ループなし」の要件を満たしていませんが、これは私がやったことです:
for m = 1:C
Z(:,:,m) = X(:,:,m)*Y;
end
これにより、A x D x C行列Zが得られます。
もちろん、Z を事前に割り当てて、 を使用して高速化することもできますZ = zeros(A,D,C);
。
関数NUM2CELLを使用して行列X
をセル配列に分割し、 CELLFUNを使用してセル全体で操作することにより、これを 1 行で実行できます。
Z = cellfun(@(x) x*Y,num2cell(X,[1 2]),'UniformOutput',false);
結果Z
は、各セルにA 行 D 列の行列が含まれる1 行 C 列のcell 配列になります。A x D x C行列にしたい場合は、CAT関数を使用できます。Z
Z = cat(3,Z{:});
注:私の古いソリューションでは、簡潔ではなかった NUM2CELL の代わりに MAT2CELL を使用していました。
[A,B,C] = size(X);
Z = cellfun(@(x) x*Y,mat2cell(X,A,B,ones(1,C)),'UniformOutput',false);
これは1行のソリューションです(3次元に分割する場合は2行):
A = 2;
B = 3;
C = 4;
D = 5;
X = rand(A,B,C);
Y = rand(B,D);
%# calculate result in one big matrix
Z = reshape(reshape(permute(X, [2 1 3]), [A B*C]), [B A*C])' * Y;
%'# split into third dimension
Z = permute(reshape(Z',[D A C]),[2 1 3]);
したがって今:Z(:,:,i)
の結果を含むX(:,:,i) * Y
説明:
上記はわかりにくいかもしれませんが、考え方は単純です。まず、 の 3 番目の次元を取り、最初の次元にX
沿って垂直方向に連結することから始めます。
XX = cat(1, X(:,:,1), X(:,:,2), ..., X(:,:,C))
...難点は変数であるため、 catまたはvertcatC
を使用してその式を一般化することはできません。次に、これに を掛けます。Y
ZZ = XX * Y;
最後に、それを 3 番目の次元に分割します。
Z(:,:,1) = ZZ(1:2, :);
Z(:,:,2) = ZZ(3:4, :);
Z(:,:,3) = ZZ(5:6, :);
Z(:,:,4) = ZZ(7:8, :);
したがって、行列の乗算が 1 回だけ必要であることがわかりますが、前後に行列を再形成する必要があります。
いいえ。いくつかの方法がありますが、それは常に直接または間接のループで発生します。
私の好奇心を喜ばせるために、なぜとにかくそれが欲しいのですか?
質問に答えて読みやすくするには、次を参照してください。
nT = 100;
t = 2*pi*linspace (0,1,nT)’;
# 2 experiments measuring 3 signals at nT timestamps
signals = zeros(nT,3,2);
signals(:,:,1) = [sin(2*t) cos(2*t) sin(4*t).^2];
signals(:,:,2) = [sin(2*t+pi/4) cos(2*t+pi/4) sin(4*t+pi/6).^2];
sT(:,:,1) = signals(:,:,1)’;
sT(:,:,2) = signals(:,:,2)’;
G = ndmult (signals,sT,[1 2]);
元のソース。インラインコメントを追加しました。
function M = ndmult (A,B,dim)
dA = dim(1);
dB = dim(2);
# reshape A into 2d
sA = size (A);
nA = length (sA);
perA = [1:(dA-1) (dA+1):(nA-1) nA dA](1:nA);
Ap = permute (A, perA);
Ap = reshape (Ap, prod (sA(perA(1:end-1))), sA(perA(end)));
# reshape B into 2d
sB = size (B);
nB = length (sB);
perB = [dB 1:(dB-1) (dB+1):(nB-1) nB](1:nB);
Bp = permute (B, perB);
Bp = reshape (Bp, sB(perB(1)), prod (sB(perB(2:end))));
# multiply
M = Ap * Bp;
# reshape back to original format
s = [sA(perA(1:end-1)) sB(perB(2:end))];
M = squeeze (reshape (M, s));
endfunction
ループを「展開」できます。つまり、ループで発生するすべての乗算を順番に書き出すことができます。
私は再帰だと思いますが、それはあなたができる他の唯一のループ以外の方法です