Related
I would like to generate all the possible combinations of the elements of a given number of vectors.
For example, for [1 2], [1 2] and [4 5] I want to generate the elements:
[1 1 4; 1 1 5; 1 2 4; 1 2 5; 2 1 4; 2 1 5; 2 2 4; 2 2 5]
The problem is that I don't know the number of vectors for which I need to calculate the combinations. There might be 3 as in this case, or there may be 10, and I need a generalization. Can you please help me to this in MATLAB? Is there already a predefined function that can do this task?
Consider this solution using the NDGRID function:
sets = {[1 2], [1 2], [4 5]};
[x y z] = ndgrid(sets{:});
cartProd = [x(:) y(:) z(:)];
cartProd =
1 1 4
2 1 4
1 2 4
2 2 4
1 1 5
2 1 5
1 2 5
2 2 5
Or if you want a general solution for any number of sets (without having to create the variables manually), use this function definition:
function result = cartesianProduct(sets)
c = cell(1, numel(sets));
[c{:}] = ndgrid( sets{:} );
result = cell2mat( cellfun(#(v)v(:), c, 'UniformOutput',false) );
end
Note that if you prefer, you can sort the results:
cartProd = sortrows(cartProd, 1:numel(sets));
Also, the code above does not check if the sets have no duplicate values (ex: {[1 1] [1 2] [4 5]}). Add this one line if you want to:
sets = cellfun(#unique, sets, 'UniformOutput',false);
Try ALLCOMB function at FileExchange.
If you store you vectors in a cell array, you can run it like this:
a = {[1 2], [1 2], [4 5]};
allcomb(a{:})
ans =
1 1 4
1 1 5
1 2 4
1 2 5
2 1 4
2 1 5
2 2 4
2 2 5
This late answers provides two additional solutions, where the second is the solution (in my opinion) and an improvement on Amro's answer solution with ndgrid by applying MATLAB's powerful comma-separated lists instead of cell arrays for high performance,
If you have the Neural Network Toolbox: use combvec
If you do not have the toolbox, as is usually the case: below is another way to generalize the Cartesian product for any number of sets.
Just as Amro did in his answer, the comma-separated lists syntax (v{:}) supplies both the inputs and outputs of ndgrid. The difference (fourth line) is that it avoids cellfun and cell2mat by applying comma-separated lists, again, now as the inputs to cat:
N = numel(a);
v = cell(N,1);
[v{:}] = ndgrid(a{:});
res = reshape(cat(N+1,v{:}),[],N);
The use of cat and reshape cuts execution time almost in half. This approach was demonstrated in my answer to an different question, and more formally by Luis Mendo.
we can also use the 'combvec' instruction in matlab
no_inp=3 % number of inputs we want...in this case we have 3 inputs
a=[1 2 3]
b=[1 2 3]
c=[1 2 3]
pre_final=combvec(c,b,a)';
final=zeros(size(pre_final));
for i=1:no_inp
final(:,i)=pre_final(:,no_inp-i+1);
end
final
Hope it helps.
Good luck.
I would like to generate all the possible combinations of the elements of a given number of vectors.
For example, for [1 2], [1 2] and [4 5] I want to generate the elements:
[1 1 4; 1 1 5; 1 2 4; 1 2 5; 2 1 4; 2 1 5; 2 2 4; 2 2 5]
The problem is that I don't know the number of vectors for which I need to calculate the combinations. There might be 3 as in this case, or there may be 10, and I need a generalization. Can you please help me to this in MATLAB? Is there already a predefined function that can do this task?
Consider this solution using the NDGRID function:
sets = {[1 2], [1 2], [4 5]};
[x y z] = ndgrid(sets{:});
cartProd = [x(:) y(:) z(:)];
cartProd =
1 1 4
2 1 4
1 2 4
2 2 4
1 1 5
2 1 5
1 2 5
2 2 5
Or if you want a general solution for any number of sets (without having to create the variables manually), use this function definition:
function result = cartesianProduct(sets)
c = cell(1, numel(sets));
[c{:}] = ndgrid( sets{:} );
result = cell2mat( cellfun(#(v)v(:), c, 'UniformOutput',false) );
end
Note that if you prefer, you can sort the results:
cartProd = sortrows(cartProd, 1:numel(sets));
Also, the code above does not check if the sets have no duplicate values (ex: {[1 1] [1 2] [4 5]}). Add this one line if you want to:
sets = cellfun(#unique, sets, 'UniformOutput',false);
Try ALLCOMB function at FileExchange.
If you store you vectors in a cell array, you can run it like this:
a = {[1 2], [1 2], [4 5]};
allcomb(a{:})
ans =
1 1 4
1 1 5
1 2 4
1 2 5
2 1 4
2 1 5
2 2 4
2 2 5
This late answers provides two additional solutions, where the second is the solution (in my opinion) and an improvement on Amro's answer solution with ndgrid by applying MATLAB's powerful comma-separated lists instead of cell arrays for high performance,
If you have the Neural Network Toolbox: use combvec
If you do not have the toolbox, as is usually the case: below is another way to generalize the Cartesian product for any number of sets.
Just as Amro did in his answer, the comma-separated lists syntax (v{:}) supplies both the inputs and outputs of ndgrid. The difference (fourth line) is that it avoids cellfun and cell2mat by applying comma-separated lists, again, now as the inputs to cat:
N = numel(a);
v = cell(N,1);
[v{:}] = ndgrid(a{:});
res = reshape(cat(N+1,v{:}),[],N);
The use of cat and reshape cuts execution time almost in half. This approach was demonstrated in my answer to an different question, and more formally by Luis Mendo.
we can also use the 'combvec' instruction in matlab
no_inp=3 % number of inputs we want...in this case we have 3 inputs
a=[1 2 3]
b=[1 2 3]
c=[1 2 3]
pre_final=combvec(c,b,a)';
final=zeros(size(pre_final));
for i=1:no_inp
final(:,i)=pre_final(:,no_inp-i+1);
end
final
Hope it helps.
Good luck.
How to generate the different combinations possible for a certain number
Example:
m=2 gives:
[1 1;1 2;2 1;2 2]
m=3 gives:
[1 1;1 2;1 3;2 1;2 2;2 3;3 1;3 2;3 3]
and so on...
using perms([1 2]) generates [1 2;2 1] only
You can use ndgrid:
m = 3;
[A,B] = ndgrid(1:m);
Here A and B look like this:
A =
1 1 1
2 2 2
3 3 3
B =
1 2 3
1 2 3
1 2 3
So you can concatenate them vertically to get the combinations. Using the colon operator transforms the matrices into column-vectors, i.e. listing all the elements column-wise. Therefore, you could use either
P = sortrows([A(:), B(:)])
or
P = [B(:) A(:)] %// Thanks #knedlsepp :)
to get sorted combinations.
P now looks like this:
P =
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
Note that your question is highly related to the following, where the goal is to find combinations from 2 vectors.: How to generate all pairs from two vectors in MATLAB using vectorised code?. I suggest you look at it as well to get more ideas.
That being said the question might be a duplicate...anyhow hope that helps.
It's a little tricky, as nchoosek can not be used straight out of the box:
n = 3;
X = nchoosek([1:n, n:-1:1],2);
Y = unique(X,'rows','legacy');
respectively in one line:
Y = unique(nchoosek([1:n, n:-1:1],2),'rows','legacy');
The following codes runs in Matlab:
a = [1 2 3 4]
b = [ 1 2 3; 1 2 3; 1 2 3]
a(b)
The result of a(b) is a matrix:
[ 1 2 3; 1 2 3; 1 2 3]
Can anyone explain what happened here? Why a vector can be indexed by a matrix, how to interpret the result?
That's a very standard MATLAB operation that you're doing. When you have a vector or a matrix, you can provide another vector or matrix in order to access specific values. Accessing values in MATLAB is not just limited to single indices (i.e. A(1), A(2) and so on).
For example, what you have there is a vector of a = [1 2 3 4]. When you try to use b to access the vector, what you are essentially doing is a lookup. The output is basically the same size as b, and what you are doing is creating a matrix where there are 3 rows, and each element accesses the first, second and third element. Not only can you do this for a vector, but you can do this for a matrix as well.
Bear in mind that when you're doing this for a matrix, you access the elements in column major format. For example, supposing we had this matrix:
A = [1 2
3 4
5 6
7 8]
A(1) would be 1, A(2) would be 3, A(3) would be 5 and so on. You would start with the first column, and increasing indices will traverse down the first column. Once you hit the 5th index, it skips over to the next column. So A(5) would be 2, A(6) would be 4 and so on.
Here are some examples to further your understanding. Let's define a matrix A such that:
A = [5 1 3
7 8 0
4 6 2]
Here is some MATLAB code to strengthen your understanding for this kind of indexing:
A = [5 1 3; 7 8 0; 4 6 2]; % 3 x 3 matrix
B = [1 2 3 4];
C = A(B); % C should give [5 7 4 1]
D = [5 6 7; 1 2 3; 4 5 6];
E = A(D); % E should give [8 6 3; 5 7 4; 1 8 6]
F = [9 8; 7 6; 1 2];
G = A(F); % G should give [2 0; 3 6; 5 7]
As such, the output when you access elements this way is whatever the size of the vector or matrix that you specify as the argument.
In order to be complete, let's do this for a vector:
V = [-1 9 7 3 0 5]; % A 6 x 1 vector
B = [1 2 3 4];
C = V(B); % C should give [-1 9 7 3]
D = [1 3 5 2];
E = V(D); % E should give [-1 7 0 9]
F = [1 2; 4 5; 6 3];
G = V(F); % G should give [-1 9; 3 0; 5 7]
NB: You have to make sure that you are not providing indexes that would make the accessing out of bounds. For example if you tried to specify the index of 5 in your example, it would give you an error. Also, if you tried anything bigger than 9 in my example, it would also give you an error. There are 9 elements in that 3 x 3 matrix, so specifying a column major index of anything bigger than 9 will give you an out of bounds error.
Notice that the return value of a(b) is the same size as b.
a(b) simply takes each element of b, call it b(i,j), as an index and returns the outputs a(b(i,j)) as a matrix the same size as b. You should play around with other examples to get a more intuitive feel for this:
b = [4 4 4; 4 4 4];
a(b) % Will return [4 4 4; 4 4 4]
c = [5; 5];
a(c) % Will error as 5 is out of a's index range
I would like to generate all the possible combinations of the elements of a given number of vectors.
For example, for [1 2], [1 2] and [4 5] I want to generate the elements:
[1 1 4; 1 1 5; 1 2 4; 1 2 5; 2 1 4; 2 1 5; 2 2 4; 2 2 5]
The problem is that I don't know the number of vectors for which I need to calculate the combinations. There might be 3 as in this case, or there may be 10, and I need a generalization. Can you please help me to this in MATLAB? Is there already a predefined function that can do this task?
Consider this solution using the NDGRID function:
sets = {[1 2], [1 2], [4 5]};
[x y z] = ndgrid(sets{:});
cartProd = [x(:) y(:) z(:)];
cartProd =
1 1 4
2 1 4
1 2 4
2 2 4
1 1 5
2 1 5
1 2 5
2 2 5
Or if you want a general solution for any number of sets (without having to create the variables manually), use this function definition:
function result = cartesianProduct(sets)
c = cell(1, numel(sets));
[c{:}] = ndgrid( sets{:} );
result = cell2mat( cellfun(#(v)v(:), c, 'UniformOutput',false) );
end
Note that if you prefer, you can sort the results:
cartProd = sortrows(cartProd, 1:numel(sets));
Also, the code above does not check if the sets have no duplicate values (ex: {[1 1] [1 2] [4 5]}). Add this one line if you want to:
sets = cellfun(#unique, sets, 'UniformOutput',false);
Try ALLCOMB function at FileExchange.
If you store you vectors in a cell array, you can run it like this:
a = {[1 2], [1 2], [4 5]};
allcomb(a{:})
ans =
1 1 4
1 1 5
1 2 4
1 2 5
2 1 4
2 1 5
2 2 4
2 2 5
This late answers provides two additional solutions, where the second is the solution (in my opinion) and an improvement on Amro's answer solution with ndgrid by applying MATLAB's powerful comma-separated lists instead of cell arrays for high performance,
If you have the Neural Network Toolbox: use combvec
If you do not have the toolbox, as is usually the case: below is another way to generalize the Cartesian product for any number of sets.
Just as Amro did in his answer, the comma-separated lists syntax (v{:}) supplies both the inputs and outputs of ndgrid. The difference (fourth line) is that it avoids cellfun and cell2mat by applying comma-separated lists, again, now as the inputs to cat:
N = numel(a);
v = cell(N,1);
[v{:}] = ndgrid(a{:});
res = reshape(cat(N+1,v{:}),[],N);
The use of cat and reshape cuts execution time almost in half. This approach was demonstrated in my answer to an different question, and more formally by Luis Mendo.
we can also use the 'combvec' instruction in matlab
no_inp=3 % number of inputs we want...in this case we have 3 inputs
a=[1 2 3]
b=[1 2 3]
c=[1 2 3]
pre_final=combvec(c,b,a)';
final=zeros(size(pre_final));
for i=1:no_inp
final(:,i)=pre_final(:,no_inp-i+1);
end
final
Hope it helps.
Good luck.