I have some different matrices with equal size, for example, say 5 different N by N matrices A1, A2, A3, A4 and A5. I want to create an N by N matrix B such that B(i, j) is the smallest element among A1(i, j), A2(i, j), A3(i, j), A4(i, j) and A5(i, j).
Since N is a big number, more efficient code is preferred.
As an alternative,
A = cat(3, A1, A2, A3, A4, A5); % store equal-size 2d arrays in 3d array
B = min(A, [], 3); % take minimum in 3rd dimension
Not the most pretty but B = min(min(min(min(A1,A2),A3),A4),A5); should work.
Related
I have a 3D matrix sized (x,y,N) and a 2D matrix sized (N,N).
I would like to manipulate the two in a way that each column in the 2D matrix has the coefficients for a linear combination of the 2D sized- (x, y) slices in the 3D matrix. And I would like to do this for all N columns in the 2D matrix.
Schematically,
Currently the code looks like:
A = zeros(numel(x_axis), numel(y_axis), N);
B = zeros(numel(x_axis), numel(y_axis), N);
C = zeros(N, N)
for i = 1 : N
for j = 1 : N
A(:,:,i) = A(:,:,i) + B(:,:,j) * C(j,i);
end
end
But it is quite slow. Is there any way to speed up the MATLAB code by vectorizing?
If I understand your problem well, then this should work:
[p,q,N] = size(B);
A = reshape( reshape(B, [p*q, N]) * C, [p, q, N]);
edit: Cleaner version suggested by Suever:
A = reshape(reshape(B, [], size(B, 3)) * C, size(B))
Generalization to the R-D case:
A = reshape(reshape(B, [], size(B, ndims(B))) * C, size(B))
You can use bsxfun which will calculate this very quickly for you. We have to use permute to re-arrange C a little bit to ensure that it has conformant dimensions for using bsxfun and then we perform the summation along the third dimension of the resulting output and apply squeeze to remove the singleton third dimension.
A = squeeze(sum(bsxfun(#times, B, permute(C, [3 4 1 2])), 3))
A is an M*N*S matrix of values and B is a P*1 vector of indices of locations in an M*N matrix. I want to get the P*S matrix, C, that is all values along 3rd direction form A, at locations specified by B (on the A(:, :, 1)).
This is my current code:
%% sample inputs
M = 2; N = 3; S = 3;
A = reshape(1:M*N*S, M, N, S)
B = (1:3:M*N)'
P = numel(B);
%% solution
B2 = repmat(B, 1, S)+repmat((0:S-1)*M*N, P, 1);
C = A(B2)
But it calls repmat twice, and I need this in a for loop that P changes in every iteration. So how can I make it more efficient?
First of all, I would strongly discourage the use of O as a variable name. It looks like a zero. Similarly, avoid a lower-case l as it looks like a 1. Below I will use S in place of your O.
You can simply reshape your initial matrix into an [M*N, S] matrix and then user the indices on the first column.
% Collapse the first two dimensions into rows
data = reshape(A, [], size(A, 3));
% Grab the rows that correspond to the indices in B
C = data(B, :);
The use of reshape is very efficient here because MATLAB doesn't need to make a copy of the underlying data, just alter how it is accessed.
I have N by M matrix A , a 1 by M matrix or a row vector B
and another 1 by M row vector C. Can I vectorize the following code more than that?
for i = 1:N
A(i,:) = (A(i,:)-B)./C;
end;
and what about more general case where we have K by M matrices(K divisible by N) instead of vectors
This is what bsxfun was designed to do:
A = bsxfun(#rdivide,bsxfun(#minus,A,B),C);
It will automatically expand the arrays of size [1 M] to be compatible with the one of size [N M], then perform the necessary array operations on them, returning an array of size [N M].
If your B and C arrays are of size [K M], then it's a bit more difficult. You didn't specify what the output should be shaped, but in the most general case you can compute "(A-B)/C" for every row of B and C and collect these matrices in an array of size [K N M]:
A = bsxfun(#rdivide,bsxfun(#minus,permute(A,[3 1 2]),permute(B,[1 3 2])),permute(C,[1 3 2]));
where A is transformed to an array of size [1 N M], and both B and C are transformed to size [K 1 M]. Depending on the size of your arrays along the various dimensions, you might benefit from putting M in front (since that's the dimension along which you're subtracting, but I'm not sure.
Unless you need raw speed, I would prefer a more explicit approach:
N = size(A, 1);
easy = (A-repmat(B, N, 1)) ./ repmat(C, N, 1);
repmat copies the first argument, the number of second argument times vertically (in rows), and they number of third argument times in columns. So, in this case, B is turned into N x M by replicating the vector N times vertically only.
For the more general case, where B & C are K x M, and N/K is an integer:
rowReps = size(A, 1)/size(B, 1);
notMuchHarder= (A - repmat(B, rowReps , 1) ./ repmat(C, rowReps, 1);
I have a n x m x d matrix A (i.e. A is like d n x m matrices). I would like to convert this into one n x m matrix B where each element B(i,j) is function of A(i,j,1), ..., A(i,j,d), more specifically the L2 norm of these values:
B(i,j) = sqrt[A(i,j,1)^2 + ... + A(i,j,d)^2]
Meaning I would like to condens or "flatten" the information in matrix A. How can I achieve this without resorting to a nested for loop?
Do elementwise squaring and sum along the third dimension to produce a N x M matrix and then apply square-root for a vectorized implementation, like so -
B = sqrt(sum(A.^2,3))
I have two matrices A and B for which I want to do a multiplication for each of their columns to produce a new matrix. The first thing cross my mind is
A = rand(4,3);
B = rand(4,3);
for J=1:SIZE(A,2)
for jj=1:size(B,2)
C(:,:,m) = A(:,j)*B(:,jj)' ;
m = m+1 ;
end
end
But I don't want to use for loops which makes it slow. Is there any way?
I am going to use the matrices of third dimension of C, the ones which are built by multiplication of columns of A and B, Is it better to first build the C and then use its 3rd dimension matrices in each loop or just do the multiplication in each loop?
One approach with bsxfun -
N1 = size(A,1);
N2 = size(B,1);
C = reshape(bsxfun(#times,permute(A,[1 4 3 2]),permute(B,[4 1 2 3])),N1,N2,[])
You could avoid going to the 4th dimension as listed next, but it's still marginally slower than the earlier 4D approach -
C = reshape(bsxfun(#times,permute(A,[1 3 2]),B(:).'),N1,N2,[])
As an alternative to Divakar's answer, you can generate all 4-fold combinations of row and column indices of the two matrices (with ndgrid) and then compute the products:
[m, p] = size(A);
[n, q] = size(B);
[mm, nn, qq, pp] = ndgrid(1:m, 1:n, 1:q, 1:p);
C = reshape(A(mm+(pp-1)*m).*B(nn+(qq-1)*n), m, n, p*q);