Submatrix / vector contingent on values in array - arrays

I have a 3D matrix A of size 20x500x68. I have two vectors carrying information regarding this matrix which are:
B (containing zeros and ones) of size 1x68 and
C (containing numbers from 1 to 3) of size 1x68
(in length both B and C correspond to the third dimension of A).
I would like to create a "sub matrix" of A only of that third dimension where B==1 and C==3.
Schematically:
[sub matrix of A] = A (B = 1, C = 3)
Is there any way to do this without a loop?

SMA = A(:,:,B==1 & C==3)
%This submatrix contains all rows and columns of that third dimension of A
%where B equals 1 and C equals 3

Related

Getting corresponding coordinates of a vectorized matrix

I have a matrix X of size n x m. I resized X to a vector a of length n x m.
How can I know "automatically" that the ith element in vector a corresponds to what element position (coordinates) in X?
I have written the following MATLAB code but I do not know how to continue.
X = rand(10,10);
[n,m] = size(X);
a = reshape(X, [n*m, 1]);
t = zeros(length(a),1);
for i = 1 : length(a)
t(i) = % I want to perform here the sum over the x and y coordinate values of the element in X
% that corresponds to the ith element in vector a.
end
Any help will be very appreciated.
That's what ind2sub does:
[row, col] = ind2sub([m n], i);
However, you may prefer to do it manually:
row = mod(i-1,m)+1;
col = floor((i-1)/m)+1;
This works because Matlab used column-major order for storing array elements. For example, in a 3×4 matrix the order in which the elements are stored in memory is as follows:
1 4 7 10
2 5 8 11
3 6 9 12
So the entry in the 2nd row, 3rd column is the 8th element in (column-major) linear order. When this matrix is reshaped into a vector (or into any other shape) this linear order is preserved. Therefore you can retrieve the original coordinates by divisions and modulus operations. Note also that, since Matlab's indexing is 1-based (as opposed to 0-based), the modulus operations need to be shifted by 1.

Compute the difference matrix between a matrix and another matrix in MATLAB

Given a matrix A in matlab with:
3 1
4 5
7 8
and another matrix B which could be referred to as some reference points (each row is reference point that is to be compared to each row of A),
1 1
1 2
I need to compute a matrix C, such that
4 5
25 18
85 72
Where each row of C is the difference (squared L2 norm) between each row of A and the rows of B. One possible way to do this in MATLAB is to first create a zero matrix C, C = zeros(5,2), and then use double for-loops to fill in the appropriate value. Is there any other efficient/simpler way in MATLAB?
Find the code snippet below
C = zeros(5,2)
for i = 1:rows
for j = 1:rows2
C(i,j) = (norm(A(i,:)-B(j,:)))^2
end
end
A solution similar to ThomasIsCoding's, but generalized to any number of dimensions (=columns). Thomas' answer requires A and B to have exactly 2 columns to use the complex representation. Here, we use a 3rd array dimension instead of complex values:
n = 3; % number of spatial dimensions for computing the L2 norm
A = 10*rand(20,n);
B = 10*rand(4,n);
C = sum((reshape(A,[],1,n) - reshape(B,1,[],n)).^2,3)
First we reshape A, such that its rows remain rows, but its columns are arranged along the 3rd array dimension. We reshape B similarly, but its rows become columns, and its columns are moved to the 3rd dimension. This arrangement of the first two dimensions match that of the output C.
Next we take the difference (using implicit singleton expansion, for older versions of MATLAB you'd need to use bsxfun), square, and sum along the 3rd dimension.
Maybe you can try bsxfun like below
A = [3,1; 4,5;7,8];
B = [1,1;1,2];
% you can first rewrite A and B in complex coordinates to simplify the computation, and then compute difference of two complex values
C = abs(bsxfun(#minus,A*[1;1j],transpose(B*[1;1j]))).^2;
and you will get
C =
4.0000 5.0000
25.0000 18.0000
85.0000 72.0000

How to create a matrix from product of all elements in two arrays?

I was reading the documentation for matlab on element-wise multiplication and I came across this example:
Create a row vector a and a column vector b, then multiply them. The
1-by-3 row vector and 6-by-1 column vector combine to produce a 6-by-3
matrix with all combinations of elements multiplied.
The documentation sure showed the output, but how did they get to that output matrix of size6,3? Which was obtained from multiplying a column vector b of size 6,1, and a row vector a of size 1,3 using the methods explained in the document.
This is called broadcasting. When one dimension is 1 while the other is bigger, the unit dimension is expanded, as if with repmat:
6 1 : column
1 3 : row
------
6 3 : result
Given
a = 1:3
b = [1:6]'
a .* b
is roughly equivalent to
a2 = repmat(a, 6, 1)
b2 = repmat(b, 1, 3)
a2 .* b2
But of course broadcasting is much more memory efficient.

Comparing a cell with a vector in Matlab

I have a cell A in Matlab of dimension 1x3, e.g.
A={{1,2,3,4} {5,6} {7,8,9} }
A contains all the integers from 1 to n in increasing order. In the example n=9. However, the number of elements within each sub-cell can be different. Each sub-cell is non-empty.
Consider the vector B of dimension nx1 containing some integers from 1 to n in increasing order (repetitions are allowed), e.g.
B=[1 1 2 2 4 7 7 8 9]'
I want to construct (without using loops) the vector C of dimension nx1 such that each C(i) tells which sub-cell of A B(i) belongs to. In the example
C=[1 1 1 1 1 3 3 3 3]'
With that structure, A is uniquely determined by the number of elements of each of its cells, and the result can be obtained as
C = sum(bsxfun(#gt, B, cumsum(cellfun(#numel, A))), 2)+1;
I don't know whether it's faster than for loops, but how about
C = arrayfun(#(b) find(cellfun(#(a) any(cell2mat(a) == b), A)), B);
Explanation: pick each element b in B; then pick every sub-cell a in A and check for equality with b, return the index of sub-cell b is a member of.

How to vectorize this matrix multiplication in matlab

I have 2 matrices A (nxm) and B (nxd) and want to multiply element-wise each column of A with a row of B. There are m columns in A and n 1xd vectors in B so the results are m nxd matrices. Then I want to sum(result_i, 1) to get m 1xd vectors, which I want to apply vertcat to get a mxd matrix. I'm doing this operations using for loop and it is slow because n and d are big. How can I vectorize this in matlab to make it faster? Thank you.
EDIT:
You're all right: I was confused by my own question. What I meant by "multiply element-wise each column of A with a row of B" is to multiply n elements of a column in A with the corresponding n rows of B. What I want to do with one column of A is as followed (and I repeat this for m columns of A, then vertcat the C's vector together to get an mxd matrix):
column_of_A =
3
3
1
B =
3 1 3 3
2 2 1 2
1 3 3 3
C = sum(diag(column_of_A)*B, 1)
16 12 15 18
You can vectorize your operation the following way. Note, however, that vectorizing comes at the cost of higher memory usage, so the solution may end up not working for you.
%# multiply nxm A with nx1xd B to create a nxmxd array
tmp = bsxfun(#times,A,permute(B,[1 3 2]));
%# sum and turn into mxd
out = squeeze(sum(tmp,1));
You may want to do everything in one line, which may help the Matlab JIT compiler to save on memory.
EDIT
Here's a way to replace the first line if you don't have bsxfun
[n,m] = size(A);
[n,d] = size(B);
tmp = repmat(A,[1 1 d]) .* repmat(permute(B,[1 3 2]),[1,m,1]);
It's ugly, but as far as I can see, it works. I'm not sure it will be faster than your loop though, plus, it has a large memory overhead. Anyway, here goes:
A_3D = repmat(reshape(A, size(A, 1), 1, size(A, 2)), 1, size(B, 2));
B_3D = repmat(B, [ 1 1 size(A, 2)]);
result_3D = sum(A_3D .* B_3D, 1);
result = reshape(result_3D, size(A, 2), size(B, 2))
What it does is: make A into a 3D matrix of size n x 1 x m, so one column in each index of the 3rd dimension. Then we repeat the matrix so we get an n x d x m matrix. We repeat B in the 3rd dimension as well. We then do a piecewise multiplication of all the elements and sum them. The resulting matrix is a 1 x d x m matrix. We reshape this into a m x d matrix.
I'm pretty sure I switched around the size of the dimensions a few times in my explanation, but I hope you get the general gist.
Multiplying with a diagonal matrix seems at least twice as fast, but I couldn't find a way to use diag, since it wants a vector or 2D matrix as input. I might try again later tonight, I feel there must be a faster way :).
[Edit] Split up the command in parts to at least make it a little bit readable.
This is the way I would do this:
sum(repmat(A,1,4).*B)
If you don't know the number of columns of B:
sum(repmat(A,1,size(B,2)).*B)

Resources