Convert output of ndgrid to a single array - arrays

I want to create an n-dimensional grid from vectors xi which specify the desired grid points in dimension i. The output should be a single N x n matrix, where N=b1*b2*b3*...*bn is the total number of grid points, and bi is the number of desired grid points along that dimension. (I want to do this in Matlab.)
I know that I can use the ndgrid function to create this n-dimensional grid, but ndgrid returns n cell arrays, each of dimension b1xb2xb3x...xbn. How can I transform this to a single array, as desired?
An additional complication: I do not know the dimension n in advance.

David already got the idea in his comment, just a minor error for n>=4.
function grid_array = ndgridarr(n, varargin)
assert(length(varargin) == 1 || length(varargin) == n);
grid_cells = cell(1, n);
[grid_cells{:}] = ndgrid(varargin{:});
grid_array = reshape(cat(n+1,grid_cells{:}),[],n);
end
An alternative is to use allcomb from file exchange or
combvec (Deep learning toolbox). They both already return a single matrix, no need to stich the cell array together.

Here's one possible solution. I'd be very happy to hear about simpler approaches.
function grid_array = ndgridarr(n, varargin)
assert(length(varargin) == 1 || length(varargin) == n);
grid_cells = cell(1, n);
[grid_cells{:}] = ndgrid(varargin{:});
grid_array = cell2mat(cellfun(#(c) c(:), grid_cells, 'UniformOutput', false));
end
You can call this function exactly like you would ndgrid, just with the additional input parameter n. (ngrid infers n automatically from the number of output arguments in the case when just a single vector is provided, but we cannot do this since we have only one output parameter in any case.)
Two examples illustrating that it does what's desired:
>> ndgridarr(3, [1,2,3])
ans =
1 1 1
2 1 1
3 1 1
1 2 1
2 2 1
3 2 1
1 3 1
2 3 1
3 3 1
1 1 2
2 1 2
3 1 2
1 2 2
2 2 2
3 2 2
1 3 2
2 3 2
3 3 2
1 1 3
2 1 3
3 1 3
1 2 3
2 2 3
3 2 3
1 3 3
2 3 3
3 3 3
>> ndgridarr(3, [1,2], [3,4], [5,6])
ans =
1 3 5
2 3 5
1 4 5
2 4 5
1 3 6
2 3 6
1 4 6
2 4 6

Related

How to remove reverse rows in a permutation matrix?

I'm looking for a quick way in MATLAB to do the following:
Given a permutation matrix of a vector, say [1, 2, 3], I would like to remove all duplicate reverse rows.
So the matrix P = perms([1, 2, 3])
3 2 1
3 1 2
2 3 1
2 1 3
1 3 2
1 2 3
becomes
3 2 1
3 1 2
2 3 1
You can noticed that, symetrically, the first element of each rows have to be bigger than the last one:
n = 4; %row size
x = perms(1:n) %all perms
p = x(x(:,1)>x(:,n),:) %non symetrical perms
Or you can noticed that the number of rows contained by the p matrix follows this OEIS sequence for each n and correspond to size(x,1)/2 so since perms output the permutation in reverse lexicographic order:
n = 4; %row size
x = perms(1:n) %all perms
p = x(1:size(x,1)/2,:) %non symetrical perms
You can use MATLAB's fliplr method to flip your array left to right, and then use ismember to find rows of P in the flipped version. At last, iterate all locations and select already found rows.
Here's some code (tested with Octave 5.2.0 and MATLAB Online):
a = [1, 2, 3];
P = perms(a)
% Where can row x be found in the left right flipped version of row x?
[~, Locb] = ismember(P, fliplr(P), 'rows');
% Set up logical vector to store indices to take from P.
n = length(Locb);
idx = true(n, 1);
% Iterate all locations and set already found row to false.
for I = 1:n
if (idx(I))
idx(Locb(I)) = false;
end
end
% Generate result matrix.
P_star = P(idx, :)
Your example:
P =
3 2 1
3 1 2
2 3 1
2 1 3
1 3 2
1 2 3
P_star =
3 2 1
3 1 2
2 3 1
Added 4 to the example:
P =
4 3 2 1
4 3 1 2
4 2 3 1
4 2 1 3
4 1 3 2
4 1 2 3
3 4 2 1
3 4 1 2
3 2 4 1
3 2 1 4
3 1 4 2
3 1 2 4
2 4 3 1
2 4 1 3
2 3 4 1
2 3 1 4
2 1 4 3
2 1 3 4
1 4 3 2
1 4 2 3
1 3 4 2
1 3 2 4
1 2 4 3
1 2 3 4
P_star =
4 3 2 1
4 3 1 2
4 2 3 1
4 2 1 3
4 1 3 2
4 1 2 3
3 4 2 1
3 4 1 2
3 2 4 1
3 1 4 2
2 4 3 1
2 3 4 1
As demanded in your question (at least from my understanding), rows are taken from top to bottom.
Here's another approach:
result = P(all(~triu(~pdist2(P,P(:,end:-1:1)))),:);
pdist computes the distance between rows of P and rows of P(:,end:-1:1).
~ negates the result, so that true corresponds to coincident pairs.
triu keeps only the upper triangular part of the matrix, so that only one of the two rows of the coincident pair will be removed.
~ negates back, so that true corresponds to non-coincident pairs.
all gives a row vector with true for rows that should be kept (because they do not coincide with any previous row).
This is used as a logical index to select rows of P.

Eliminate repeated vectors but with elements on different order

I have a matrix A which is (243 x 5). I want to pick the unique row vectors of that matrix but taking into account that row vectors with the same elements but in different order shall be considered as being the same.
E.g., suppose for simplicity that the A matrix is (10 x 5) and equal to:
A=[1 2 1 2 3
1 3 1 1 1
1 3 1 1 2
1 2 1 1 3
2 3 1 2 1
1 3 1 2 2
1 3 1 2 3
1 3 1 3 2
1 3 1 3 1
1 3 2 3 1]
On the example above, rows (1, 5, 6) are to be considered equivalent they have the same elements but in different order. Also, rows (3 and 4) are equivalent, and rows (7, 8, 10) are also equivalent.
Is there any way to write a code that removes all "repeated rows", i.e. a code that delivers only the rows (1, 2, 3, 7 and 9) from A?
So far I came across with this solution:
B(:,1) = sum(A == 1,2);
B(:,2) = sum(A == 2,2);
B(:,3) = sum(A == 3,2);
[C, ia, ic] = unique(B,'rows');
Result = A(ia,:);
This delivers what I am looking for with one caveat - it is delivering the unique rows of A according to the criteria defined above, but it is not delivering the first row it finds. I.e. instead of delivering rows (1,2,3,7,9) it is delivering rows(7, 1, 9, 3, 2).
Anyway I can force him to deliver the rows in correct order? Also any better way of doing this?
You can do it as follows:
Sort A along the second dimension;
Get stable indices of unique (sorted) rows;
Use the result as row indices into the original A.
That is:
As = sort(A, 2);
[~, ind] = unique(As, 'rows', 'stable');
result = A(ind,:);
For
A = [1 2 1 2 3
1 3 1 1 1
1 3 1 1 2
1 2 1 1 3
2 3 1 2 1
1 3 1 2 2
1 3 1 2 3
1 3 1 3 2
1 3 1 3 1
1 3 2 3 1];
this gives
result =
1 2 1 2 3
1 3 1 1 1
1 3 1 1 2
1 3 1 2 3
1 3 1 3 1

Create groups of sub-matrices according to one column

I would like to know how to create groups of matrices starting from a Matrix in Matlab.
I have this Matrix :
A= [ 1 1 2
1 2 3
1 3 4
2 1 3
2 2 4
2 3 5
3 1 4
3 2 5
3 3 6]
Now I would like to create several new matrices in which the elements, of each new matrix, are the first two columns of each row in A that have the third column of A in common.
For this case will be :
Af1=[1 1] % elements in common '2' (third column of A)
Af2= [1 2
2 1] % elements in common '3' (third column of A)
and so on.
Thanks in advance
Here's another approach:
B = sortrows(A, size(A,2)); %// sort rows acording to last column
gs = diff(find(diff([inf; B(:,3); inf])~=0)); %// sizes of groups determined by last col
result = mat2cell(B(:,1:end-1), gs); %// split according to those group sizes
This is a job for accumarray:
[ofGroup,~,subs] = unique(A(:,3));
values = accumarray(subs,1:size(A,1),[],#(x) {A(x,[1,2])});
out = [ofGroup values]
For accessing the result you could use the approach proposed by Divakar using deal. But I'd rather rethink and use the cell array out directly:
>> out{3,2}
ans =
1 3
2 2
3 1
You can use one approach with unique & arrayfun -
[~,~,idx] = unique(A(:,3),'rows','stable')
out = arrayfun(#(n) A(idx==n,1:2),1:max(idx),'Uni',0)
Verify output with celldisp -
>> celldisp(out)
out{1} =
1 1
out{2} =
1 2
2 1
out{3} =
1 3
2 2
3 1
out{4} =
2 3
3 2
out{5} =
3 3
Or if you already know how many groups you would have and would like to save each such cell as a new matrix with names Af1, Af2, etc., you can use deal (distribute inputs to outputs) -
>> [Af1,Af2,Af3,Af4,Af5] = deal(out{:})
Af1 =
1 1
Af2 =
1 2
2 1
Af3 =
1 3
2 2
3 1
Af4 =
2 3
3 2
Af5 =
3 3

Matching two matrices depending on diagonal elements of two matrices in matlab

Below are the two adjacency matrices.I have to find which row of matrix1 is correspond to which row in matrix2 depending on diagonal values.In below example
1st row=1st row(diagonal value=4)
2nd row=5th row(diagonal value=5)
3rd row=4th row(diagonal value=1)
4th row=2nd row(diagonal value=3)
5th row=3rd row(diagonal value=2)
4 4 1 3 2
4 5 1 3 2
1 1 1 1 1
3 3 1 3 2
2 2 1 2 2
4 3 2 1 4
3 3 2 1 3
2 2 2 1 2
1 1 1 1 1
4 3 2 1 5
How it can be done in matlab?
Use the second output of ismember:
[~, result] = ismember(diag(matrix1), diag(matrix2))
In your example, this returns
result =
1
5
4
2
3
Assuming mat1 and mat2 to be the first and second matrices respectively and that you are looking to find the first match of diagonal values, try this -
[~,ind] = max(bsxfun(#eq,diag(mat2),diag(mat1)'))
or
[~,ind] = max(bsxfun(#eq,diag(mat1),diag(mat2)'),[],2)
If you are certain that there are always unique matches, you can use find too -
[ind,~] = find(bsxfun(#eq,diag(mat2),diag(mat1)'))

All row-combinations of a matrix in a new matrix with matlab

I have got a question regarding all the combinations of matrix-rows in Matlab.
I currently have a matrix with the following structure:
1 2
1 3
1 4
2 3
2 4
3 4
Now I want to get all the possible combinations of these "pairs" without using a number twice in the same row:
1 2 3 4
1 3 2 4
1 4 2 3
And it must be possible to make it with n-"doublecolumns". Which means, when my pair-matrix goes for example until "5 6", i want to create the matrix with 3 of these doublecolumns:
1 2 3 4 5 6
1 2 3 5 4 6
1 2 3 6 4 5
1 3 2 4 5 6
1 3 2 5 4 6
....
I hope you understand what I mean :)
Any ideas how to solve this?
Thanks and best regard
Jonas
M = [1 2
1 3
1 4
2 3
2 4
3 4]; %// example data
n = floor(max(M(:))/2); %// size of tuples. Compute this way, or set manually
p = nchoosek(1:size(M,1), n).'; %'// generate all n-tuples of row indices
R = reshape(M(p,:).', n*size(M,2), []).'; %// generate result...
R = R(all(diff(sort(R.'))),:); %'//...removing combinations with repeated values

Resources