How to repeat each dimension of a 3-D matrix in matlab - arrays

Say I have a 3-D matrix a of dimension [X,Y,Z],
a(:,:,1) = [1 2; 3 4];
a(:,:,2) = [5 6; 7 8];
Is there a way to repeat each entry of a, say N times and construct a new matrix, b, of dimension [X, Y, N*Z]? For example, if N=2, to have a matrix b like so,
%repeat first element of 'a' 2ce
b(:,:,1) = [1 2; 3 4];
b(:,:,2) = [1 2; 3 4];
%repeat second element of 'a' 2ce
b(:,:,3) = [5 6; 7 8];
b(:,:,4) = [5 6; 7 8];
Using a nested loop can achieve this of course, for e.g.
%not tested, but should work
b = zeros(X,Y,N*Z);
k=1;
for j=1:Z
for i=1:N
b(:,:,k) = a(:,:,j);
k=k+1;
end
end
But I'll like to know if there's an inbuilt function available for this purpose.

Create an index of the form 1,1,2,2,... (example for N=2) and use it in the third dimension:
b = a(:,:,ceil(1/N:1/N:size(a,3)));

Related

Matlab diff command with bigger step

The command diff calculates differences between two consecutive elements. Is there any way to calculates differences between two nonconsecutive elements?
For example, with
x = [1,2,3,4,5,6]
is there any command to find
[x(3)-x(1),x(4)-x(2),x(5)-x(3),x(6)-x(4)] = [2,2,2,2]
or
[x(4)-x(1),x(5)-x(2),x(6)-x(3)] = [3,3,3]
And in general, for the case of a matrix? I can write some code for this; I just wonder if there any existing command in Matlab for this?
An example of the matrix case
x = [1,2,3,4;1,3,5,7;2,4,6,8]
and we want to find
[x(1,3)-x(1,1),x(1,4)-x(1,2);x(2,3)-x(2,1),x(2,4)-x(2,2);x(3,3)-x(3,1),x(3,4)-x(3,2)] = [2,2;4,4;4,4]
For vectors
I would use convolution with kernel [1 0 ยทยทยท 0 -1], where the number of zeros depends on the desired step. This can be done with function conv:
x = [1,2,3,4,5,6]; % data
s = 2; % step
result = conv(x, [1 zeros(1,s-1) -1], 'valid');
gives
result =
2 2 2 2
For matrices or N-dimensional arrays
The above can be generalized using convn, with a kernel defined as before but oriented along the desired dimension:
x = [1,2,3,4; 1,3,5,7; 2,4,6,8]; % data
s = 2; % step
d = 2; % dimension
result = convn(x, reshape(([1 zeros(1,s-1) -1]), [ones(1,d-1) s+1 1]), 'valid');
gives
result =
2 2
4 4
4 4
I'm not aware of such a function, but you can simply set up a very simple anonymous function
stepDiff = #(x, s) x(:, s:end)-x(:, 1:end-s+1);
Will give outputs like:
x = [1, 2, 3, 4, 5, 6];
>> stepDiff(x, 2)
ans =
1 1 1 1 1
>> stepDiff(x, 4)
ans =
3 3 3
x = [1, 2, 3, 4; 1, 3, 5, 7; 2, 4, 6, 8];
>> stepDiff(x, 3)
ans =
2 2
4 4
4 4

Sort structure according another array

I have structure A which is to be sorted according to ascending order of array c.
A.a=[2 3 1]
A.b=[5 3 6]
c=[4 2 1]
[c1 c2]=sort(c)
A=A(c2) % It is not working
Index exceeds matrix dimension error is shown.
I think you want to use structfun
A.a = [2 3 1]
A.b = [5 3 6]
c = [4 2 1]
[~, c2] = sort(c)
A = structfun(#(x) x(c2), A, 'UniformOutput', false)
But it seems that all of your vectors are of the same length. Why not store them as rows in a matrix instead of a struct?
A = [2 3 1; 5 3 6]
c = [4 2 1]
[~, c2] = sort(c)
A = A(:, c2)
Probably you just need to change the format of A, this works
A(1).a = 2; A(1).b = 5;
A(2).a = 3; A(2).b = 3;
A(3).a = 1; A(3).b = 6;
c=[4 2 1];
[c1 c2]=sort(c);
A = A(c2);
If you don't want to change the structure of A (but then I guess the whole exercise doesn't make sense at all), then you need to sort each field seperately
A.a = A.a(c2);
A.b = A.b(c2);

Matlab - Accessing a part of a multidimensional array

I'm trying to access a part of a multidimensional array in Matlab - it could be done like this: X(2:3, 1:20, 5, 4:7)
However, neither the number of elements, nor the ranges are fixed, so I want to provide the indices from arrays - for the above example they'd be
ind1 = [2 1 5 4];
ind2 = [3 20 5 7];
For a fixed number of dimensions this is not a problem (X(ind1(1):ind2(1),...), but since they are not I'm not sure how to implement this in Matlab. Is there a way? Or should I approach this differently?
Using comma separated lists you can make it a more quick and friendly:
% some test data
ind1 = [2 1 5 4];
ind2 = [3 20 5 7];
X = randi(99,20,20,20,20);
% get all subscripts in column format
vecs = arrayfun(#colon,ind1,ind2,'un',0);
% extract the values
result = X(vecs{:});
There probably is a more elegant way, but this is a difficult problem so here is one solution:
% some test data
ind1 = [2 1 5 4];
ind2 = [3 20 5 7];
X = randi(99,20,20,20,20);
% get all subscripts in column format
vecs = arrayfun(#colon,ind1,ind2,'Uniformoutput',false);
subs = combvec(vecs{:}).';
% manual sub2ind for a matrix where each row contains one subscript
sizeX = size(X);
idx = cumprod([1 sizeX(1:end-1)])*(subs - [zeros(size(subs,1),1) ones(size(subs,1),size(subs,2)-1)]).';
% reshape
result = reshape(X(idx),ind2-ind1+1);
Subscripts to indices conversion based on Gnovices answer in Indexing of unknown dimensional matrix

Subtract second column from two matrices based on first column

Let say I have 2 matrices A (7x2) and B (3x2)
A = [1 5;2 6;3 7;4 8;5 9;6 10;7 11]
B = [2 4;4 7;5 3]
The result that I want is:
C = [2 2;4 1;5 6]
ismember does the job too:
>> C = [B(:,1) A(ismember(A(:,1),B(:,1)),2) - B(:,2)]
C =
2 2
4 1
5 6
Or if not all of B(:,1) is in A:
[m,locs] = ismember(B(:,1),A(:,1))
C = [A(locs,1) A(locs,2) - B(m,2)]
you want intersect
that way it will work even if A doesn't have to be in order or have all numbers from 1.
A = [1 5;2 6;3 7;4 8;5 9;6 10;7 11]
B = [2 4;4 7;5 3]
[cc,ia,ib] = intersect(A(:,1),B(:,1))
C = [cc,A(ia,2)-B(ib,2)]

How do I multiply 3 vectors and obtain a 3D matrix in MATLAB?

What I'm trying to do is obtain results like the snippet below without a loop.
x = [1 2 3 4];
y = [2 3 4];
z=[7 8];
[x'*y]
for k=1:size(z, 2)
z2(:,:,k)=[x'*y]*z(k);
end
z2
Loops may slow down MATLAB, however. How do I approach the task without them?
You can just do this because z is ` vector:
bsxfun(#times, reshape(z, 1, 1, []), [x'*y])
If z was a 2D matrix itself and you wanted to do a matrix multiplication at each level then you would need to use the links I posted in my comment. But because each time you are multiplying by a scalar, you can use #times.
Have a look here. Base on this, you could do as follows:
x = [1 2 3 4];
y = [2 3 4];
z=[7 8];
% replicate [x'*y] into 3D array.
d = repmat([x'*y], [1, 1, numel(z)])
% multiplay by z vector
z2 = bsxfun(#times, d, reshape(z,[1, 1, numel(z)]))

Resources