Getting the mapping for a permutation in MATLAB - matlab

Say I have two arrays where one is a permutation of the other:
A = [2 1 5 3 7]
B = [7 2 1 3 5]
with no repetitions in either array.
How can I obtain the permutation mapping between both?
E.g. A->B should be:
[2, 3, 5, 4, 1]
which means:
A(1) -> B(2)
A(2) -> B(3)
A(3) -> B(5)
A(4) -> B(4)
A(5) -> B(1)
Update:
Is there a fast vectorized solution that does not use ismember ? In my experience, ismember tends to be slow for very large arrays.

How about this:
[i a] = sort(A);
[i b] = sort(B);
mapping = b(a)

Use ismember.
[~,idx] = ismember(A,B);
The vector idx will contain indices such that B(idx) == A.
Note that ismember finds the highest indices.

You can also use knnsearch, but for not repeated members in both a and b

Try this:
for i=1:size(B)
C(:,i) = [i find(B==A(i))]
end

Related

MATLAB : 3 dimensional matrix with multipication with a vector

I have A matrix which is 16x16x155460. I have a B vector which is 12955x1. I want to multiply each 1:16x1:16x1+12*n:12+12*nwith the elements of B(n). So my goal is to find the weighted sum of the A according to B. My way to do this as follows (I don't want to use for-loop and my method gives wrong answer, I could not obtain the 1:12 vectors which is consecutive) :
B = repmat(B,[1 16 16]);
B = permute(B,[2 3 1]);
B = repmat(B,[1 1 12]);
result = B.*(A);
As a small example n=2 :
A(:,:,1)=[1 2; 3 4]
A(:,:,2)=[1 2; 3 4]
A(:,:,3)=[1 2; 3 4]
A(:,:,4)=[1 2; 3 4]
B = [2,3]
Result would be:
result(:,:,1)=A(:,:,1)*B(1);
result(:,:,2)=A(:,:,2)*B(1);
result(:,:,3)=A(:,:,1)*B(2);
result(:,:,4)=A(:,:,2)*B(2);
If I understood the problem correctly, you can use the powerful trio of bsxfun, permute and reshape to solve it, like so -
[M,N,R] = size(A);
mult_out = bsxfun(#times,reshape(A,M,N,numel(B),[]),permute(B(:),[4 3 1 2]))
out = reshape(mult_out,M,N,[])

Comparison between vectors in matlab

if i have A=[3 4 5 6] and B=[6 5 4] then i want to compare each value in A with all values in B,
if this value is greater then increase counter with 1 and if this value is equal then increase another counter with 1
If you want an array that corresponds to the result of each value in A, you could do
arrayfun(#(x) sum(x > B), A)
this gives [0, 0, 1, 2]. If you want the total sum you would just put sum(...) around that:
sum(arrayfun(#(x) sum(x > B), A))
this gives 3.
For the equal-counter, you can simply change > to ==:
arrayfun(#(x) sum(x == B), A)
this gives [0, 1, 1, 1].
Another approach in comparison to arrayfun would be bsxfun. Though it takes a bit more memory, I'd argue that it's faster. arrayfun is implicitly a for loop and using loops in MATLAB is usually slower than vectorized approaches.
If you want the greater than case, use the gt function with bsxfun, so:
>> A = [3 4 5 6];
>> B = [6 5 4];
>> sum(bsxfun(#gt, A, B.'), 1)
ans =
0 0 1 2
If you want to accumulate all of the values that match the criterion, you can put another sum call within this bsxfun call:
>> sum(sum(bsxfun(#gt, A, B.'), 1))
ans =
3
For the greater than or equal case, use ge:
>> sum(bsxfun(#ge, A, B.'), 1)
ans =
0 1 2 3
For the equality case, use eq:
>> sum(bsxfun(#eq, A, B.'), 1)
ans =
0 1 1 1
Again, if you want to accumulate all of the values that match the criterion, nest another sum call with the above results.

Find row-wise combinations of a 2 dimensional matrix

I have a matrix:
X = [2,6,1; 3,8,1; 4,7,1; 6,2,1; 6,4,1; 7,3,1; 8,5,1; 7,6,1];
I want to find all row-wise combinations of X. i.e.
A(1) = [2, 6, 1; 3, 8, 1; 4, 7, 1]
A(2) = [2, 6, 1; 3, 8, 1; 6, 2, 1]
:
:
:
Here's what I've tried:
X = [2,6,1; 3,8,1; 4,7,1; 6,2,1; 6,4,1; 7,3,1; 8,5,1; 7,6,1];
p = 3
[m, n] = size(X);
comb = combnk(1:m, p);
[s, t] = size(comb);
c = [X(comb(:,1), :, :) X(comb(:,2), :, :) X(comb(:,3), :, :)];
This gives me a matrix like:
c = 2 6 1 3 8 1 4 7 1
2 6 1 3 8 1 6 2 1
2 6 1 3 8 1 6 4 1
I want to apply the concatenate matrix option to obtain c to make it dynamic depending on value of p but I'm not sure how to use it. I don't want to use For loops. Please help me out.
This is fully vectorized, so it should be fast:
n = 3; %// number of rows to pick each time
ind = reshape(nchoosek(1:size(X,1), n).', [], 1); %'// indices of combinations
A = permute(reshape(X(ind,:).', size(X,2), n, []), [2 1 3]);
The result is
A(:,:,1)
ans =
2 6 1
3 8 1
4 7 1
A(:,:,2)
ans =
2 6 1
3 8 1
6 2 1
etc.
Should you need the result in the form of a cell array, you can convert A from 3D-array to cell array this way:
A = mat2cell(A, size(A,1), size(A,2), ones(1,size(A,3)));
Your thinking is pretty close. This code does the job. I put comments in code, which should be easy to read.
X = [2,6,1; 3,8,1; 4,7,1; 6,2,1; 6,4,1; 7,3,1; 8,5,1; 7,6,1];
p = 3;
%// List all combinations choosing 3 out of 1:8.
v = nchoosek(1:size(X,1), p);
%// Use each row of v to create the matrices, and put the results in an cell array.
%// This is the A matrix in your question.
A = arrayfun(#(k)X(v(k,:), :), 1:size(v,1), 'UniformOutput', false);
%// And you can concatenate A vertically to get c.
flatA = cellfun(#(x)reshape(x, 1, []), A, 'UniformOutput', false);
c = vertcat(flatA{:});
PS: From my understanding I thought the result you wanted was A, which is an easy to use cell array. But I added an extra step to get c exactly as in your question just in case.
Disclaimer: arrayfun and cellfun are pretty much equivalent to for loop in terms of performance.
You can do it using reshape and a bunch of transposes since Matlab is column-major ordered:
c = reshape(X(comb',:)',9,[])'
or if you want a 3D matrix:
A = permute(reshape(X(comb',:)',3,3,[])', [2,1,3])

Find part of vector in another vector matlab

I would like to know if there is an easy way to find the indices of a vector in another vector in matlab:
a = [1 2 3 5 7 10 2 3 6 8 7 5 2 4 7 2 3]
b = [2 3]
So how to get the indices of a when comparing it with b (index of first element is needed)
In this case:
ans = [2 7 16]
Thanks in advance
find(a(1:end-1) == b(1) & a(2:end) == b(2) == 1)
You can re-purpose strfind by converting the elements of both vectors to byte arrays (uint8) with typecast:
bytesPerEl = numel(typecast(a(1),'uint8'));
byteLocs = strfind(char(typecast(a,'uint8')),char(typecast(b,'uint8')));
locsb = (byteLocs-1)/bytesPerEl + 1
locsb =
2 7 16
Just make sure a and b are of the same type. Also note that this works for 1D vectors, not matrixes or higher dimensional arrays.
General approach with length of b arbitrary (not necessarily 2 as in the example), and avoiding the use of strings:
match1 = bsxfun(#eq, a(:), b(:).'); %'// now we just need to make the diagonals
%// horizontal (in order to apply "all" row-wise). For that we'll use indices
%// ind, ind1, ind2
ind = reshape(1:numel(match1), numel(a), numel(b));
ind1 = nonzeros(tril(ind)); %// source indices
ind2 = sort(nonzeros(tril(flipud(ind)))); %// destination indices
match2 = zeros(size(match1));
match2(ind2) = match1(ind1); %// diagonals have become horizontal
result = find(all(match2.'));

what is the easiest way to find out whether one vector is rotation of another?

Let's assume we have a = [1 2 3 4], b = [3 4 1 2] and c = [1 2 4 3].
What is the easiest way to find out that b is the shift of a and c is not the shift of a?
And is there some functions for matrixes?
I suggest you use strfind. If a is a rotation of b, then a should be found inside [b b]:
strfind([b b],a)
ans =
3
>> strfind([c c],a)
ans =
[]
You can rotate a size(a) times and check if the newly rotated vector is the same with b:
for i = 1:length(a),
a = a([end 1:end-1])
if(a == b)
disp('true')
end
end