Complete set of combinations combining 3 set - arrays

I need to generate the complete set of combinations obtained combining three different subset:
Set 1: choosing any 4 numbers from a vector of 13 elements.
Set 2: choosing any 2 numbers from a vector of 3 elements.
Set 3: choosing any 2 numbers from a vector of 9 elements.
Example: sample 3 from vector of 4 (H=3 and L=4) for the Set A, H=2 L=3 for the Set B and H=2 L=4 for the Set B:
4 4 4
3 4 4
3 3 4
3 3 3
2 4 4
2 3 4
2 3 3
2 2 4
Set A = 2 2 3
2 2 2
1 4 4
1 3 4
1 3 3
1 2 4
1 2 3
1 2 2
1 1 4
1 1 3
1 1 2
1 1 1
3 3
2 3
Set B = 2 2
1 3
1 2
1 1
4 4
3 4
3 3
2 4
Set C = 2 3
2 2
1 4
1 3
1 2
1 1
[Set A] = [20 x 3], [Set B] = [6 x 2], [Set C] = [10 x 2]. Then I need to obtain all possible combinations from these three sets: AllComb = [Set A] x [Set B] x [Set C] = [1200 x 8]. The AllComb matrix will be like this:
4 4 4 | 3 3 | 4 4
4 4 4 | 3 3 | 3 4
4 4 4 | 3 3 | 3 3
4 4 4 | 3 3 | 2 4
4 4 4 | 3 3 | 2 3
4 4 4 | 3 3 | 2 2
4 4 4 | 3 3 | 1 4
4 4 4 | 3 3 | 1 3
4 4 4 | 3 3 | 1 2
4 4 4 | 3 3 | 1 1
4 4 4 | 2 3 | 4 4
4 4 4 | 2 3 | 3 4
4 4 4 | 2 3 | 3 3
4 4 4 | 2 3 | 2 4
4 4 4 | 2 3 | 2 3
.
.
.
1 1 1 | 1 1 | 1 1
Unfortunately I can not use the same number for the sets since I need to substitute the numbers like that:
For Set A: 1 = 10, 2 = 25, 3 = 30 and 4 = 45
For Set B: 1 = 5, 2 = 20 and 3 = 35
For Set C: 1 = 10, 2 = 20, 3 = 30 and 4 = 50
Any ideas? Real case sets will often lead to an AllComb matrix ~[491 400 x 8] so vectorized solutions will be gladly accepted.
Note: Each set is obtained with the following code:
a = combnk(1:H+L-1, H);
b = cumsum([a(:,1) diff(a,[],2) - 1],2);
What is H and L?
H are the hoppers of a MultiheadWeigher (MHW) machines. I have a MHW with H=8 and I need to deliver in each of these hoppers some materials. If I need to deliver just one type of material all possibile combinations are (L+H-1)!/(H!(L-1)!) and i compute them with the code write above (a and b). Now, suppose to have 3 different product then we have 4 hoppers for product A, 2 for B and 2 for C. Product A in the first 4 hoppers can assume values 10:10:130, Product B 10:10:30 and c 10:10:90. Then the number of steps are for A L=13, B L=3 and C L=9

You basically need to find
Combinations with repetition for each set;
"Multi-variations" (I don't know the correct name for this) of the results of stage 1.
Both stages can be solved with more or less the same logic, taken from here.
%// Stage 1, set A
LA = 4;
HA = 3;
SetA = cell(1,HA);
[SetA{:}] = ndgrid(1:LA);
SetA = cat(HA+1, SetA{:});
SetA = reshape(SetA,[],HA);
SetA = unique(sort(SetA(:,1:HA),2),'rows');
%// Stage 1, set B
LB = 3;
HB = 2;
SetB = cell(1,HB);
[SetB{:}] = ndgrid(1:LB);
SetB = cat(HB+1, SetB{:});
SetB = reshape(SetB,[],HB);
SetB = unique(sort(SetB(:,1:HB),2),'rows');
%// Stage 1, set C
LC = 4;
HC = 2;
SetC = cell(1,HC);
[SetC{:}] = ndgrid(1:LC);
SetC = cat(HC+1, SetC{:});
SetC = reshape(SetC,[],HC);
SetC = unique(sort(SetC(:,1:HC),2),'rows');
%// Stage 2
L = 3; %// number of sets
result = cell(1,L);
[result{:}] = ndgrid(1:size(SetA,1),1:size(SetB,1),1:size(SetC,1));
result = cat(L+1, result{:});
result = reshape(result,[],L);
result = [ SetA(result(:,1),:) SetB(result(:,2),:) SetC(result(:,3),:) ];
result = flipud(sortrows(result)); %// put into desired order
This gives
result =
4 4 4 3 3 4 4
4 4 4 3 3 3 4
4 4 4 3 3 3 3
4 4 4 3 3 2 4
4 4 4 3 3 2 3
4 4 4 3 3 2 2
4 4 4 3 3 1 4
4 4 4 3 3 1 3
4 4 4 3 3 1 2
4 4 4 3 3 1 1
4 4 4 2 3 4 4
4 4 4 2 3 3 4
4 4 4 2 3 3 3
4 4 4 2 3 2 4
4 4 4 2 3 2 3
4 4 4 2 3 2 2
4 4 4 2 3 1 4
4 4 4 2 3 1 3
4 4 4 2 3 1 2
...

I guess this could be further optimized but this generates you AllComb:
H=3;
L=4;
a = combnk(1:H+L-1, H);
b = cumsum([a(:,1) diff(a,[],2) - 1],2);
H=2;
L=3;
c = combnk(1:H+L-1, H);
d = cumsum([c(:,1) diff(c,[],2) - 1],2);
H=2;
L=4;
e = combnk(1:H+L-1, H);
f = cumsum([e(:,1) diff(e,[],2) - 1],2);
u=[];
for k=1:10
u=vertcat(u,d);
end
u=sortrows(u,[1 2]);
v=[];
for k=1:6
v= vertcat(v,f);
end
w= [u,v];
v=[];
for k=1:20
v= vertcat(v,w);
end
u=[];
for k=1:60
u = vertcat(u,b);
end
u=sortrows(u,[1 2 3]);
AllComb= [u,v];
Here b,d and f are your 3 sets. Then i loop over the numbers of permutation in d and f and replicate them so that all possibilities are constructed. One of them is sorted and then i write them in a new matrix w. THis process is repeated with Set A (b) and this new constructed matrix. Resulting in the end in AllComb.

Related

From ndgrid grid-representing matrices to grid points

By using ndgrid, we can obtain the matrices representing the grid:
[Y, X, Z]=ndgrid(1:2,3:4,5:6)
Y(:,:,1) =
1 1
2 2
Y(:,:,2) =
1 1
2 2
X(:,:,1) =
3 4
3 4
X(:,:,2) =
3 4
3 4
Z(:,:,1) =
5 5
5 5
Z(:,:,2) =
6 6
6 6
However, there are actually 8 grid "points"
(3,1,5), (3,1,6), (3,2,5), (3,2,6), (4,1,5), (4,1,6), (4,2,5), (4,2,6)
How can I create a matrix of these 8 vectors (using ndgrid or not in the process)? That is,
3 1 5
3 1 6
3 2 5
3 2 6
4 1 5
4 1 6
4 2 5
4 2 6
I've seen this related question, but it uses meshgrid, which only works for two dimensions.
Easy. Just linearize the output from ndgrid:
[Y, X, Z]=ndgrid(1:2,3:4,5:6);
out = [X(:) Y(:) Z(:)]
If you want the same ordering as in your question, use sortrows:
out = sortrows([X(:) Y(:) Z(:)])
You just need to straighten these 3D vectors:
>> vertices = [X(:),Y(:),Z(:)]
vertices =
3 1 5
3 2 5
4 1 5
4 2 5
3 1 6
3 2 6
4 1 6
4 2 6

Taking averages of data based on logical filter

we have two columns ('A' and 'B') as follows.
A = [10 5 6 6 10 2 3 2 1 3 2 3 3 7 9 8 6 8 8 12]
B = [10 5 6 6 2 2 3 2 1 3 2 3 3 7 2 2 3 3 8 12]
logicalFilter= ~(B<=3 & B>1)
Now I need to take averages of data points in A corresponding to logicalFilter == 1 for three different blocks of logicalFilter == 1 separately and also ignoring first two points (for example) in A when logicalFilter == 1 in each block for the calculation of averages. How this can be done?
My mentalist skills leading me to this answer:
%// input
A = [10 5 6 6 10 2 3 2 1 3 2 3 3 7 9 8 6 8 8 12]
B = [10 5 6 6 2 2 3 2 1 3 2 3 3 7 2 2 3 3 8 12]
mask = (B<=3 & B>1)
%// get subs and vals for accumarray
C = cumsum(~mask) + 1
[~,~,subs] = unique(C(mask))
val = A(mask)
%// calculate mean starting with 3rd value of group
out = accumarray(subs(:),val(:),[],#(x) mean(x(3:end)) )
out =
2.5000 3.0000 7.0000

How to sort rows of a matrix based on frequency of the elements of one column?

I tried using sortrows function in Matlab. Is there any way using this function or any idea to sort rows of a matrix based on frequency of elements of a column of that matrix.
As an example: I have this matrix
matrix = [1 3 1;
1 4 2;
2 5 4;
3 2 3;
5 5 4;
5 3 3;
4 3 2;
4 2 3;
3 6 4;
2 4 3];
I would like to get something similar to this:
sorted_based_on_3rd_col = [2 4 3;
3 2 3;
4 2 3;
5 3 3;
2 5 4;
3 6 4;
5 5 4;
1 4 2;
4 3 2;
1 3 1]
which is sorted based most frequent element on third column.
Thanks for any help!
This is one way:
x = matrix(:,3);
[c,b] = histc(x,unique(x))
[~,idx] = sort(c(b),'descend')
out = matrix(idx,:)
If you don't care about the order of elements with equal frequency, this can be done like so:
>> freq = accumarray(matrix(:,3), 1);
>> [~, ind] = sort(freq(matrix(:, 3)), 1, 'descend'); % index that sorts matrix
>> matrix(ind, :) % reshuffle matrix to sort
ans =
3 2 3
5 3 3
4 2 3
2 4 3
2 5 4
5 5 4
3 6 4
1 4 2
4 3 2
1 3 1
If you do care, you need to pre-sort the matrix before anything else. Since matlab's sort is stable, this will preserve the order of items that are equal in the second sort.
>> matrix = sortrows(matrix, 1)
matrix =
1 3 1
1 4 2
2 5 4
2 4 3
3 2 3
3 6 4
4 3 2
4 2 3
5 5 4
5 3 3
>> freq = accumarray(matrix(:,3),1);
>> [~, ind] = sort(freq(matrix(:,3)), 1, 'descend');
>> matrix(ind, :)
ans =
2 4 3
3 2 3
4 2 3
5 3 3
2 5 4
3 6 4
5 5 4
1 4 2
4 3 2
1 3 1

Unique Columns Across an Array?

I have an array structured like so:
a = [1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 4 4 4 4 5 5 5 5;
1 1 1 1 2 2 2 2 2 2 2 1 1 1 1 2 2 3 3 1 1 1 2 3 4 4 4 1 1 1 1 2 2 3 3];
Pretty much, it's a 2 by n (I simplified my matrix in this question with reduced number of columns for simplicity's sake), no real pattern. I want to be able to find the unique number of columns. So in this simplified example, I can (but it'll take a while) count by hand and noticed that my unique matrix b is:
b= 1 1 2 2 2 3 3 3 3 4 5 5
1 2 1 2 3 1 2 3 4 1 2 3
In MATLAB, I can do something like
size(b,2)
To get the number of unique columns. In this example
size(b,2) = 12
My question is, how do I go from matrix a to matrix b so that I can do this computationally for very large n dimensional matrices that I have?
Use unique:
a = [1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 4 4 4 4 5 5 5 5;
1 1 1 1 2 2 2 2 2 2 2 1 1 1 1 2 2 3 3 1 1 1 2 3 4 4 4 1 1 1 1 2 2 3 3];
% Transpose to leverage the rows flag, then transpose back
b = unique(a.', 'rows').';
Which returns:
b =
1 1 2 2 2 3 3 3 3 4 5 5
1 2 1 2 3 1 2 3 4 1 2 3

How to concatenate submatrix into a bigger matrix in Octave

I'm trying to solve the following issue: I have an 3x3x4 array like this:
A(:,:,1) = A(:,:,2) = A(:,:,3) = A(:,:,4) =
1 1 1 2 2 2 3 3 3 4 4 4
1 1 1 2 2 2 3 3 3 4 4 4
1 1 1 2 2 2 3 3 3 4 4 4
I would like to produce a 6x6 matrix like the following:
B =
1 1 1 3 3 3
1 1 1 3 3 3
1 1 1 3 3 3
2 2 2 4 4 4
2 2 2 4 4 4
2 2 2 4 4 4
My first thought was to use something like the reshape function, but since it operates columnwise, the result is not what I want.
Do you have any ideas to perform it efficiently?
Thanks in advance
This is for a general case of converting a 3D array into such a 2D array -
m = 2; %// number of 3D slices to be vertically concatenated to form the rows
m1 = size(A,1)*m;
m2 = size(A,3)/m;
B = reshape(permute(reshape(permute(A,[1 3 2]),m1,m2,[]),[1 3 2]),m1,[])
Sample run -
A(:,:,1) =
1 1 7
1 9 1
1 7 2
A(:,:,2) =
3 9 2
9 4 7
9 3 7
A(:,:,3) =
2 6 8
4 8 4
1 8 4
A(:,:,4) =
1 1 7
8 3 4
1 9 8
A(:,:,5) =
7 9 2
6 8 5
4 1 6
A(:,:,6) =
3 2 8
4 9 1
4 4 4
B =
1 1 7 2 6 8 7 9 2
1 9 1 4 8 4 6 8 5
1 7 2 1 8 4 4 1 6
3 9 2 1 1 7 3 2 8
9 4 7 8 3 4 4 9 1
9 3 7 1 9 8 4 4 4
Since your sub-matrices are all of the same size you can assign them directly into B:
clear
B = zeros(6);
A(:,:,1) = ones(3);
A(:,:,2) = 2*ones(3);
A(:,:,3) = 3*ones(3);
A(:,:,4) = 4*ones(3);
B = [A(:,:,1) A(:,:,3); A(:,:,2) A(:,:,4)]
B =
1 1 1 3 3 3
1 1 1 3 3 3
1 1 1 3 3 3
2 2 2 4 4 4
2 2 2 4 4 4
2 2 2 4 4 4
This might prove cumbersome if you have many more sub-matrices though but that could be automated.
permute is much more efficient (à la Divakar) or manually slicing into a 2D array (à la Benoit), but I'll add something to the mix for future readers. One way I can suggest is to take each plane and place it into a 1D cell array, reshape the cell array into a 2 x 2 grid, then convert the 2 x 2 grid into a final matrix. Something like:
B = arrayfun(#(x) A(:,:,x), 1:4, 'uni', 0);
B = reshape(B, 2, 2);
B = cell2mat(B)
B =
1 1 1 3 3 3
1 1 1 3 3 3
1 1 1 3 3 3
2 2 2 4 4 4
2 2 2 4 4 4
2 2 2 4 4 4

Resources