MATLAB vectorization to create a matrix - matlab

I want to create a matrix like
[1 2;
1 3;
1 4;
1 5;
2 3;
2 4;
2 5;
3 4;
3 5;
4 5 ]
when the size is 5. I aim to have sizes greater than 100. How can I create a matrix like this using vertorization in MATLAB?

You're looking for binomial coefficients, so use the built-in nchoosek command. For example, the matrix in your question can be generated by:
A = nchoosek(1:5, 2)
This results in:
A =
1 2
1 3
1 4
1 5
2 3
2 4
2 5
3 4
3 5
4 5

One solution:
[r,c]=find(tril(ones(N),-1));
result = [c,r];
As a bonus, you can get the number of rows in such matrix with
nrows = nchoosek(N,2);

Related

Auto-fill matrix without row-repetitions

I have a series of numbers:
test = [1 1 1 2 2 2 3 3 3 4 4 4 5 5 5]
which I want to randomely fill into a 3x5 matrix without having the same number in the same row.
How can I do this in matlab? Potentially I could randomize the test vector and fill it into the 5x3 matrix but I don't know how to do this without getting the same number in the same row.
If you want to fill a 3-by-5 matrix with all of the values in test, making sure each row has no repeated values, you can do this very succinctly by using toeplitz to first generate an index matrix, then randomly permute the dimensions with randperm:
index = toeplitz(1:3, [3 5:-1:2]);
index = index(randperm(3), randperm(5));
And a sample index:
index =
1 5 4 2 3
4 3 2 5 1
5 4 3 1 2
If your values in test are the numbers 1 through 5, this should be all you need to do. If test could be any vector with with 5 different numbers, three of each, then you can get the unique values of your test vector and index them with index. This solution will generalize to any test vector:
test = [3 3 3 7 7 7 5 5 5 9 9 9 4 4 4]; % Sample data
uniqueValues = unique(test); % Get the unique values [3 4 5 7 9]
M = uniqueValues(index); % Use index as generated above
And the result will be guaranteed to be a reordered version of what's in test:
M =
3 9 7 4 5
7 5 4 9 3
9 7 5 3 4
You can take the unique matrix of test and pick any three elements out of it and fill in the required 5X3 matrix.
test = [1 1 1 2 2 2 3 3 3 4 4 4 5 5 5] ;
test_unique = unique(test) ;
A = zeros(5,3) ;
for i = 1:size(A,1)
A(i,:) = randsample(test_unique,3) ;
end
randsample needs a statistics toolbox, if you doesn't have it, you may use randperm as shown below.
test = [1 1 1 2 2 2 3 3 3 4 4 4 5 5 5] ;
test_unique = unique(test) ;
A = zeros(5,3) ;
for i = 1:size(A,1)
A(i,:) = test_unique(randperm(length(test_unique),3)) ;
end
If you want 3X5 matrix:
test = [1 1 1 2 2 2 3 3 3 4 4 4 5 5 5] ;
test_unique = unique(test) ;
A = zeros(3,5) ;
for i = 1:size(A,1)
A(i,:) = randsample(test_unique,5) ;
end
Here is a brute-force way of doing it
% data
test = [1 1 1 2 2 2 3 3 3 4 4 4 5 5 5];
% randomly permute the indices
indices = randperm(numel(test));
% create a random matrix
matrix = reshape(test(indices), 5, 3);
% while number of unique elements in any of the rows is other than 3
while any(arrayfun(#(x) numel(unique(matrix(x,:))), (1:size(matrix,1)).')~=3)
% keep generating random matrices
indices = randperm(numel(test));
matrix = reshape(test(indices), 5, 3);
end;
% here is the result
result=matrix;
EDIT : If you want 3x5 like you mentioned in your comment, it is a lot easier. Just one line below.
[~, result] = sort(rand(3,5),2);

permutation of separate rows of matrix

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))

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);

Sorting Coordinate Matrix in Matlab

In Matlab I have a big matrix containing the coordinates (x,y,z) of many points (over 200000). There is an extra column used as identification. I have written this code in order to sort all coordinate points. My final goal is to find duplicated points (rows with same x,y,z). After sorting the coordinate points I use the diff function, two consecutive rows of the matrix with the same coordinates will take value [0 0 0], and then with ismember I can find which rows of that matrix resulting from applying "diff" have the [0 0 0] row. With the indices returned from ismember I can find which points are repeated.
Back to my question...This is the code I wrote to sort properly my coordintes+id matrix. I guess It could be done better. Any suggestion?
%coordinates are always positive
a=[ 1 2 8 4; %sample matrix
1 0 5 6;
2 4 7 1;
3 2 1 0;
2 3 5 0;
3 1 2 8;
1 2 4 8];
b=a; %for checking purposes
%sorting first column
a=sortrows(a,1);
%sorting second column
for i=0:max(a(:,1));
k=find(a(:,1)==i);
if not(isempty(k))
a(k,:)=sortrows(a(k,:),2);
end
end
%Sorting third column
for i=0:max(a(:,2));
k=find(a(:,2)==i);
if not(isempty(k))
%identifying rows with same value on first column
for j=1:length(k)
[rows,~] = ismember(a(:,1:2), [ a(k(j),1),i],'rows');
a(rows,3:end)=sortrows(a(rows,3:end),1);
end
end
end
%Checking that rows remain the same
m=ismember(b,a,'rows');
if length(m)~=sum(m)
disp('Error while sorting!');
end
Why don't you just use unique?
[uniqueRows, ii, jj] = unique(a(:,1:3),'rows');
Example
a = [1 2 3 5
3 2 3 6
1 2 3 9
2 2 2 8];
gives
uniqueRows =
1 2 3
2 2 2
3 2 3
and
jj =
1
3
1
2
meaning third row equals first row.
If you need the full unique rows, including the fourth column: use ii to index a:
fullUniqueRows = a(ii,:);
which gives
fullUniqueRows =
1 2 3 9
2 2 2 8
3 2 3 6
Trying to sort a based on the fourth column? Do this -
a=[ 1 2 8 4; %sample matrix
1 0 5 6;
2 4 7 1;
3 2 1 0;
2 3 5 0;
3 2 1 8;
1 2 4 8];
[x,y] = sort(a(:,4))
sorted_a=a(y,:)
Trying to get the row indices having repeated x-y-z coordinates being represented by the first three columns? Do this -
out = sum(squeeze(all(bsxfun(#eq,a(:,1:3),permute(a(:,1:3),[3 2 1])),2)),2)>1
and use it similarly for sorted_a.

How can I sum specific values of a column corresponding to unique values of another column, without using the "accumarray" command?

I have a matrix in matlab:
a=[1 1; 1 2; 1 3; 2 1; 2 5; 2 7; 3 2; 3 1; 3 4];
if
a1=[1 1 1 2 2 2 3 3 3]; is the first column
and
a2=[1 2 3 1 5 7 2 1 4]; is the second column
of this matrix, I want for the repeated values "unique(a1)" of a1 to sum the corresponding values of a2, so as to get this:
a3=[1+2+3 1+5+7 2+1+4]=[6 13 7]
but without using the "accumarray" command
Any help please?
My consolidator tool does this for you, even offering a tolerance.
[a1cons,a2cons] = consolidator(a1',a2',#sum)
a1cons =
1
2
3
a2cons =
6
13
7