permutation of separate rows of matrix - matlab

How to effectively vectorize the following MATLAB code, which performs permutation of each row of matrix R by indices in corresponding row of matrix P?
for i = 1:size(P,1)
pP(i,:) = R(i,P(i,:));
end
example:
P = [3 2 1;
3 1 2;
2 3 1;
2 1 3;
1 2 3;
1 3 2]
R = [6 5 4;
6 4 5;
5 6 4;
5 4 6;
4 5 6;
4 6 5]
produce following matrix pR:
4 5 6
5 6 4
6 4 5
4 5 6
4 5 6
4 5 6

One approach with bsxfun -
nrows = size(R,1)
pP = R(bsxfun(#plus,[1:nrows]',(P-1)*nrows))
Or with ndgrid -
[m,n] = size(R)
pP = R(sub2ind([m n],ndgrid(1:m,1:n),P))
Or replace ndgrid(1:m,1:n) with repmat: repmat([1:m]',[1 n]) or with meshgrid:meshgrid(1:m,1:n).'.

This might not be the best way to do it, but you could do something like:
IND1 = P(:,1)
Q(:,1) = diag(R(:,IND));
and repeat for P(:,2), P(:,3) in a similar fashion.

You can use arrayfun to avoid the loop but probably won't gain in performance if that it is the reason for vectorizing it:
cell2mat(arrayfun(#(k) R(k, P(k,:)), (1:size(P,1)).', 'uni', 0))

Related

Reshape 59x16 double into 236x4?

How can I reshape a matrix in MATLAB, preferably using reshape?
A simple matrix setup:
A = [1 4 7 10; 2 5 8 11; 3 6 9 12]
that I want to reshape into
B = [1 4; 2 5; 3 6; 7 10; 8 11; 9 12]
I've tried numerous settings of reshape, but I cannot figure it out.
1 2 3 4
5 6 7 8
reshaped into
1 2
5 6
3 4
7 8
You can use reshape and permute:
reshape(permute(reshape(A,size(A,1),2,[]),[1 3 2]),[],2)
Thanks to #LuisMendo that suggests a modification to the answer to avoid depending on the size of A.
If I understand the transformation properly it is:
A = [1 4 7 10; 2 5 8 11; 3 6 9 12]
B = A(:,1:end/2);
B = [B;A(:,end/2+1:end)];
Is this correct?
EDIT:
Or the general case:
function [B] = elefaaant(A,n)
[a,b] = size(A);
if mod(b,n) ~= 0
error('Cannot reshape')
end
B = zeros(a*n,b/n);
fac = b/n;
for i = 1:n
B((i-1)*a+1:i*a,:) = A(:,(i-1)*fac+1:i*fac);
end
B = A(:,1:end/2);
B = [B;A(:,end/2+1:end)];
C = B(:,1:end/2);
C = [C;B(:,end/2+1:end)];
Maybe it can be done in a simpler way, but seems to work.

How to compare in Matlab two matrices of different dimension and get the frequency of equal rows?

I have matrix A in Matlab of dimension hxk and a matrix B of dimension yxk. I want to construct a vector C of dimension yx1 listing in each row j how many times B(j,:) appears in A.
If you are looking for perfect matches, one solution with bsxfun -
C = squeeze(sum(all(bsxfun(#eq,A,permute(B,[3 2 1])),2),1))
You can also use pdist2 (from the Statistics Toolbox):
C = sum(pdist2(A, B)==0);
Another solution using ismember and accumarray
A=[1 2 3; 4 5 6; 7 8 9; 1 2 3; 4 5 6; 10 11 12; 7 8 9];
B=[1 2 3; 10 11 12; 3 4 5; 7 8 9];
[uB,aB,cB]=unique(B,'rows');
[~,LocB] = ismember(A,uB,'rows');
C = accumarray(nonzeros(LocB),1,[size(B,1),1]);
C=C(cB);
which returns
C =
2 1 0 2
or some crazy coding which seems to be faster for most instances:
[u,v,w]=unique([B;A],'rows');
wB=w(1:size(B,1));
wA=w(size(B,1)+1:end);
C=accumarray(wA,1,[numel(v),1]);
C=C(wB);

How do I re organize the rows of a matrix using a vector in Octave?

I am trying to achieve something stupid here and I am struck at this one point.
Say I have a matrix X which is 5 * 3 and I have a vector B which is 5 * 1
X = [6 5 3;
4 5 6;
3 8 9;
7 8 9;
1 2 3]
B = [1;
5;
4;
2;
3]
How do I reorganize my X using B to get the order of indexes as indicated in B.
What I want to happen is ..
X = someoperation(X, B)
and X should be
X = [6 5 3;
1 2 3;
7 8 9;
4 5 6;
3 8 9]
I could write a function to do this but I see that inbuilt function are faster than functions that I write.
You don't need any functions, this is a simple case of subscript indexing, a basic feature of the language:
X(B,:)

How do I Combine two equal sized vectors element wise in MatLab?

I have two vectors:
a = [1 3 5 7 9];
b = [2 4 6 8 10];
That I need to combine together element wise. Meaning that I need the first element of vector a, then the first element of vector b, second of a, second of b, and so forth until I get the following:
combined = [1 2 3 4 5 6 7 8 9 10]
How do I do this within MatLab?
Edit
I ran a test of the top three answers (Josh, Marc, & Kronos) and compared the time it took to run them. I ran each 100 times after doing a 10 iteration warmup. The vectors created were exactly the same size in length (16e+6) and were random values ranging from 1 to 100:
Test Results
Test: Total Time (100 runs): Avg Time Per Exec:
Josh B 21.3687 0.2137
Marc C 21.4273 0.2143
Kronos 31.1897 0.3119
It appears that both Josh's and Marc's solutions are similar in execution time.
a = [1 3 5 7 9];
b = [2 4 6 8 10];
temp = [a; b];
combined = temp(:)';
This can be done by the following:
a = [1 3 5 7 9];
b = [2 4 6 8 10];
combinedSize = size(a, 2) * 2;
combined(1:2:combinedSize) = a;
combined(2:2:combinedSize) = b;
This is obviously assuming that your vectors are exactly the same size. If by chance you want to merge two vectors that are not the same size then you can do the following:
combinedSize = max(size(a, 2), size(b, 2)) * 2;
combined = NaN(1,combinedSize);
combined(1:2:size(a,2)*2) = a;
combined(2:2:size(b,2)*2) = b;
This will place a NaN for the remaining elements of the smaller vector. For example, given the following sample vectors:
a = [1 3 5 7 9 11];
b = [2 4 6 8];
will result in the combined vector:
combined =
1 2 3 4 5 6 7 8 9 NaN 11 NaN
Place the vectors below eachother in a matrix and use reshape. For example:
>> A=[1 2 3]
A =
1 2 3
>> B=[4 5 6]
B =
4 5 6
>> C=reshape([A;B],1,size(A,2)+size(B,2))
C =
1 4 2 5 3 6
It's straightforward to generalize to more than 2 vectors.
You can also give a try to looping, for example:
a=[1 2 3 4 5];
b=[11 12 13 14 15];
for i = 1:N
{
if (i%2==0)
{ c[i] = b[i]; }
else
{ c[i] = a[i]; }
This shall work!
All the answers above only work if the two vectors have the same number of elements. The following will work even if they have different number of elements:
>>
A = [1 3 5];
B = [2 4 6 7 8];
C = [1 3 5 7 8];
D = [2 4 6];
AB = nan(1,2*max(numel(A),numel(B)));
CD = nan(1,2*max(numel(C),numel(D)));
AB(2*(1:length(A))) = A;
AB(1+2*(1:length(B))) = B;
CD(2*(1:length(C))) = C;
CD(1+2*(1:length(D))) = D;
>>
AB = AB(~isnan(AB))
CD = CD(~isnan(CD))
The result would be:
AB =
1 2 3 4 5 6 7 8
CD =
1 2 3 4 5 6 7 8

Change order of rows in a matrix in MATLAB

I need to transform a matrix:
X = [1 2; 3 4; 5 6; 7 8]
X = 1 2
3 4
5 6
7 8
to
X = [1 2; 5 6; 3 4; 7 8]
X = 1 2
5 6
3 4
7 8
and do this operation for a matrix with any number of rows. So that in a matrix with 200 rows, row 101 will become row 2, row 102 will become row 4 and so on.
How can I achieve this in MATLAB?
For arrays with an even number of rows, you do the following:
nRows = size(X,1);
idx = [1:nRows/2;nRows/2+1:nRows];
X_rearranged = X(idx(:),:);
For arrays with odd number of rows, you add 1 to nRows, and use idx(1:end-1) instead of idx(:)
You can use:
X = [1 2; 3 4; 5 6; 7 8]
Y = [a(1,:); a(3,:); a(2,:); a(4,:)]