How to put 1st dimension along 3rd in Matlab? - matlab

Suppose I have a matrix
A=[1 2 3]
which is row matrix. Not I want to do it "page" matrix, i.e. align elements along 3rd dimension.
I noticed, that the following
A=permute(A,[3 1 2])
works, while the following
A=permute(A,[3 2 1])
does not.
Why?

Your question is not really clear. If I'm right you'd like your matrix to become B = [0,0,1;0,0,2; 0,0,3].
This can be done easily with the transpose function by typing:
B(:,:,3)=A'
Instead of using the permute function which is a generalization of transpose. Also, your operation might not "work" because permute is an operation that affects the dimension of the array, and not of its elements

Note that the size of A is [1 3], not [3 1]. As CST-Link points out, this is equivalent with [1 3 1 1] etc., since the singleton dimensions are removed.
size(A,1) = 1
size(A,2) = 3 <-- You want this to be the third dimension
size(A,3) = 1
Now, what you want to do is align the second dimension (the one telling you how many columns you have) to the third dimension (the one telling you how many slices you have).
When you use permute, you specify the order you want the original dimensions to occur. I.e. if you do permute(A, [2 1]) for a vector, you will transpose it. The second dimension is now the first and vice versa. You want the second dimemsion to be the third, and keep the first dimension constant, so:
permute(A, [1 3 2])
If you do:
permute(A, [3 2 1])
you will take the third dimension to be the first (size(A,1) = 1), the second dimension (size(A,2) = 3) will be the second (i.e. it is not changed), and the first dimension is the third. Thus, the only dimensions that change are the first and third. These are both 1 to begin with, so nothing has changed.
Note that you can also use shiftdim in this particular case:
shiftdim(A,-1)

Related

Allocating elements from a smaller matrix to a bigger one by user input

I have 3 smaller matrices (in multidimensional arrays), all of them 4x4. I want to build a bigger matrix (8x8) for each smaller one, but rearranging the position of each element of the smaller matrix into a new position in the bigger one, according to user matrix input:
For example, I have those 3 little matrices:
A=repmat(1, [4 4]);
B=repmat(2, [4 4]);
C=repmat(3, [4 4]);
and the bigger one K=zeros(8);. The user input matrix is this one:
user=[1 2 7 8; 3 4 1 2; 3 4 7 8];
So the first bigger matrix must have a configuration where:
The red numbers are the new row and columns in the bigger matrix, resulting in this for K:
How can I insert values from the smaller matrices to the bigger matrix in this way?
It is not clear why you need this, but this is the solution I thought.
K = zeros(8,8);
for ii=1:4
for jj=1:4
K(user(1,ii),user(1,jj)) = A(ii,jj);
K(user(2,ii),user(2,jj)) = B(ii,jj);
K(user(3,ii),user(3,jj)) = C(ii,jj);
end
end
You can easily do this by using a row of user as the row and column indices into K, like so:
K(user(1, :), user(1, :)) = A;
If you want to iterate over each smaller matrix and user input, inserting them all into the same larger matrix K, I'd first put the smaller matrices into a single cell array, then simply repeat the above in a for loop:
smallMats = {A, B, C};
K = zeros(8);
for row = 1:size(user, 1)
K(user(row, :), user(row, :)) = smallMats{row};
end
This can easily be extended to more matrices by adding to user and smallMats.

How to generate evenly space for a vector?

Generating evenly space can use linspace, but I wonder if I can vectorize it. What I mean is as follow:
Given an input vector, say [1 2], I want to generate a 2X6 matrix such that:
in the first row, the entries are [0:0.2:1]
the entries for the second row are [0:0.4:2]
In general, the input vector may not be known, it can change from [1 2] to [1:3:10] or other vectors. However, the first column much be a zero vector and the number of columns can be treated to be the known in advanced.
I do not want to write it using a for loop if possible.
Assuming A = [x, y], you can generate the desired 2 x 6 matrix M as follows:
B = A/A(1);
M = B.'*linspace(0, A(1), 6);

Dividing each slice of a MATLAB 3D array by a different number

I have a 3D MATLAB function.
I want to multiply each slice of the matrix by a different number.
I tried to implement this by bsxfun in the following example code:
a=randi(10,4,3,2);
b=[2 3];
c=bsxfun(#times,a,b)
I intended that the first 4*3 slice of 'a' would be multiplied by 2, and the second 4*3 slice of 'a' would be multiplied by 3.
However, I only got the following error:
??? Error using ==> bsxfun
Non-singleton dimensions of the two
input arrays must match each other.
How to solve the problem without using a loop?
As the error says, you need to make the dimensions of the vector and the matrix match. Since b is a row vector, you can make the slices of the matrix into columns. You can do this with permute:
a = randi(10, 4, 3, 2);
b = [2 3];
ap = permute(a, [1 3 2]);
c = bsxfun(#times, ap, b)
Then, to get the result matrix back into the correct shape, you need to permute again. You can either figure out the correct permutation order (it happens to be the same in this case, i.e. [1 3 2]) or you can use ipermute (inverse permute) and let it figure it out for you. Just give it the same permutation order you gave permute earlier.
c = ipermute(c, [1 3 2]);
Alternatively, you can permute the vector b to be the right shape to multiply the slices by making it extend in the 3rd dimension:
a = randi(10, 4, 3, 2);
b = [2 3];
bp = permute(b, [1 3 2]);
c = bsxfun(#times, a, bp)
In this case, since we didn't change a, we don't have to permute c again to get the correct shape.

Change 1D vector (nx1) to 3D matrix (1x1xn)

Given a= [1;2;3] I want to change this to b where b is
b(1,1,1) = 1
b(1,1,2) = 2
b(1,1,3) = 3.
How can I do this? Is there no built-in command for this?
Use permute to throw the first dimension back at the end as third dimension and bring the third and second dimensions to the front (their orders won't matter). Thus, we would have two such implementations, like so -
permute(a,[3 2 1])
permute(a,[2 3 1])
You can also use reshape to push back the elements to the third dimension, like so -
reshape(a,1,1,numel(a))
Little tutorial on permute
A 3D array A without any permute(rearrangement of dimensions) changes would be : permute(A,[1 2 3]).
Now, any permuting you do, would be w.r.t. the original order of [1 2 3]. Let's say you want to swap 1st and 3rd dimensions, so swap the 1 and 3 in [1 2 3], giving us [3 2 1] and use it as the second argument in permute.
Here's to make your permuting skills stronger - Let's say, you swap first and third dimensions and then you do some processing on this permuted 3D array. Now, you want to get back to the original order, so you need to swap back the 1st and 3rd dimensions. So, you use [3,2,1] again, like so - permute(permute(A,[3 2 1]),[3 2 1]) and this would be essentially permute(A,[1 2 3]) and yes that's A, back to home!
You can also use
b = shiftdim(a,-2);
As per the documenation,
B = shiftdim(X,N) shifts the dimensions of X by N. When N is
positive, shiftdim shifts the dimensions to the left and wraps the
N leading dimensions to the end. When N is negative, shiftdim
shifts the dimensions to the right and pads with singletons.
A singleton dimension [or simpliy "singleton"] is any dimension dim for which size(A,dim) = 1.

Check element wise equality of a 3D matrix Matlab

I have a 3D matrix say for eg. A(10x5x8). I need to get a 2D matrix (Boolean) out of it of size 10x5.
True if its elemental 3 Dimensional values are all same. i.e. Result(1,1) = 1 if A(1,1,1) == A(1,1,2) == A(1,1,3) etc..
False if at least one is different.
I expect a vectored approach which is fast and efficient.
Sample input:
A(:,:,1) = 1 2
2 2
A(:,:,2) = 1 1
2 3
Expected Output:
Result = 1 0
1 0
Use bsxfun with the eq function and use the first slice as the first input and compare with the other slices for the second input. Allow the first input to broadcast itself over the multiple slices.
Once you do that, use all and check the third dimension:
ind1 = bsxfun(#eq, A(:,:,1), A(:,:,2:end);
ind2 = all(ind1, 3);
The logic behind the above is very simple. How the first line of code works is that you would create a temporary matrix that would take the first slice of A and let it duplicate itself for as many slices as you have in A, without the first slice. Once you do this, you would do an element-by-element equality with this temporary matrix and the other slices. If you had a 3D column that was all equal, the one element from the first slice would be compared with every single value that corresponds to the same 3D column. Should they all equal to each other, then you would get a 3D column of all logical 1s. Therefore, to have a 3D column that is all equal to each other, all of the values should be 1, which is why all is used - to check if all values in a 3D column are equal to 1. Should all of the 3D column be a logical 1, we have matched your criteria.
Example run
>> A1 = [1 2; 2 2];
>> A2 = [1 1; 2 3];
>> A3 = [1 3; 2 4];
>> A4 = [1 5; 2 6];
>> A = cat(3, A1, A2, A3, A4);
>> ind1 = bsxfun(#eq, A(:,:,1), A(:,:,2:end);
>> ind2 = all(ind1, 3)
ind2 =
1 0
1 0
I made a matrix of 4 slices where the 3D column at the top left corner and the bottom left corner have all of the same values. Once you run through the code at the beginning of the post, we get what you expect.
Here's with short and sweet diff and must be quite memory efficient -
out = ~any(diff(A,[],3),3)
So, basically with diff along the third dimension diff(..[],3), you would calculate differences between the same (i,j) but on different 3D slices. Thus, if all such diff outputs are zeros, that would indicate that all dim3 elements for the same (i,j) are the same. This all zeros information is then picked up by ~any() also along dim3 with ~any(.,3) for the desired 2D array output.