Reputation: 4855
I have a constant 2D double matrix mat1
. I also have a 2D cell array mat2
where every cell contains a 2D or 3D double matrix. These double matrices have the same number of rows and columns as mat1
. I need to dot multiply (.*) mat1
with every slice of each double matrix within mat2
. The result needs to be another cell array results
with the same size as mat2
, whereby the contatining double matrices must equal the double matrices of mat2
in terms of size.
Here's my code to generate mat1
and mat2
for illustrating purposes. I am struggling at the point where the multiplication should take place.
rowCells = 5;
colCells = 3;
rowTimeSeries = 300;
colTimeSeries = 5;
slices = [1;10];
% Create 2D double matrix
mat1 = rand(rowTimeSeries, colTimeSeries);
% Create 2D cell matrix comprisiong 2D and/or 3D double matrices
mat2 = cell(rowCells,colCells);
for c = 1:colCells
for r = 1:rowCells
slice = randsample(slices, 1, true);
mat2{r,c} = rand(rowTimeSeries, colTimeSeries, slice);
end
end
% Multiply (.*) mat1 with mat2 (every slice)
results = cell(rowCells,colCells);
for c = 1:colCells
for r = 1:rowCells
results{r,c} = ... % I am struggling here!!!
end
end
Upvotes: 0
Views: 293
Reputation: 627
I had almost the exact same answer as Wolfie but he beat me to it.
Anyway, here is a one liner that I think is slightly nicer:
nR = rowCells; % Number of Rows
nC = colCells; % Number of Cols
results = arrayfun(@(I) bsxfun(@times, mat1, mat2{I}), reshape(1:nR*nC,[],nC), 'un',0);
This uses arrayfun
to perform the loop indexing and bsxfun
for the multiplications.
A few advantages
1) Specifying 'UniformOutput'
('un'
) in arrayfun
returns a cell array so the results
variable is also a cell array and doesn't need to be initialised (in contrast to using loops).
2) The dimensions of the indexes determine the dimensions of results
at the output, so they can match what you like.
3) The single line can be used directly as an input argument to a function.
Disadvantage
1) Can run slower than using for
loops as Wolfie pointed out in the comments.
Upvotes: 1
Reputation: 30046
You could use bsxfun
to remove the need for your custom function multiply2D3D
, it works in a similar way! Updated code:
results = cell(rowCells,colCells);
for c = 1:colCells
for r = 1:rowCells
results{r,c} = bsxfun(@times, mat1, mat2{r,c});
end
end
This will work for 2D and 3D matrices where the number of rows and cols is the same in each of your "slices", so it should work in your case.
You also don't need to loop over the rows and the columns of your cell array separately. This loop has the same number of iterations, but it is one loop not two, so the code is a little more streamlined:
results = cell(size(mat2));
for n = 1:numel(mat2) % Loop over every element of mat2. numel(mat2) = rowCells*colCells
results{n} = bsxfun(@times, mat1, mat2{n});
end
Upvotes: 1
Reputation: 4855
One solution I came up with is to outsource the multiplication of a 2D with a 3D matrix into a function. However, I am curious to know whether this is the most efficient way to solve this problem?
rowCells = 5;
colCells = 3;
rowTimeSeries = 300;
colTimeSeries = 5;
slices = [1;10];
% Create 2D double matrix
mat1 = rand(rowTimeSeries, colTimeSeries);
% Create 2D cell matrix comprisiong 2D and/or 3D double matrices
mat2 = cell(rowCells,colCells);
for c = 1:colCells
for r = 1:rowCells
slice = randsample(slices, 1, true);
mat2{r,c} = rand(rowTimeSeries, colTimeSeries, slice);
end
end
% Multiply (.*) mat1 with mat2 (every slice)
results = cell(rowCells,colCells);
for c = 1:colCells
for r = 1:rowCells
results{r,c} = multiply2D3D(mat1, mat2{r,c});
end
end
function vout = multiply2D3D(mat2D, mat3D)
%MULTIPLY2D3D multiplies a 2D double matrix with every slice of a 3D
% double matrix.
%
% INPUTs:
% mat2D:
% 2D double matrix
%
% mat3D:
% 3D double matrix where the third dimension is equal or greater than 1.
%
% OUTPUT:
% vout:
% 3D double matrix with the same size as mat3D. Every slice in vout
% is the result of a multiplication of mat2D with every individual slice
% of mat3D.
[rows, cols, slices] = size(mat3D);
vout = zeros(rows, cols, slices);
for s = 1 : slices
vout(:,:,s) = mat2D .* mat3D(:,:,s);
end
end
Upvotes: 0